gene_pool 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +10 -0
- data/History.md +28 -0
- data/{LICENSE → LICENSE.txt} +1 -1
- data/README.md +61 -0
- data/Rakefile +30 -12
- data/lib/gene_pool.rb +140 -26
- data/test/gene_pool_test.rb +70 -22
- metadata +39 -54
- data/.gitignore +0 -3
- data/History.txt +0 -20
- data/README.rdoc +0 -44
- data/VERSION +0 -1
- data/gene_pool.gemspec +0 -49
data/Gemfile
ADDED
data/History.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
GenePool Changelog
|
2
|
+
=====================
|
3
|
+
|
4
|
+
1.2.0 / 2011-12-07
|
5
|
+
|
6
|
+
- Allow dynamic modification of pool size.
|
7
|
+
- Added close method which will prevent checking out of new connections and wait for and close all current connections.
|
8
|
+
- Added remove_idle method which will close all current connections which have been idle for the given idle_time.
|
9
|
+
- with_connection_auto_retry no longer accepts an argument (it defaulted to true previously) because of the addition
|
10
|
+
of the close_proc option which defaults to :close. This should be set to nil if no closing is necessary
|
11
|
+
(Deepest apologies for making an incompatible change if anyone is actually using this argument).
|
12
|
+
|
13
|
+
1.1.1 / 2010-11-18
|
14
|
+
|
15
|
+
- In with_connection_auto_retry, add check for e.message =~ /expired/ as JRuby exception won't be a
|
16
|
+
Timeout::Error at this point (http://jira.codehaus.org/browse/JRUBY-5194)
|
17
|
+
|
18
|
+
1.1.0 / 2010-11-11
|
19
|
+
|
20
|
+
- Added with_connection_auto_retry to automatically retry yield block if a non-timeout exception occurs
|
21
|
+
|
22
|
+
1.0.1 / 2010-09-12
|
23
|
+
|
24
|
+
- Debug logging was NOT thread-safe
|
25
|
+
|
26
|
+
1.0.0 / 2010-09-05
|
27
|
+
|
28
|
+
- Initial release
|
data/{LICENSE → LICENSE.txt}
RENAMED
data/README.md
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# gene_pool
|
2
|
+
|
3
|
+
* http://github.com/bpardee/gene_pool
|
4
|
+
|
5
|
+
## DESCRIPTION:
|
6
|
+
|
7
|
+
Generic pooling library for connection pools.
|
8
|
+
|
9
|
+
## FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* Thread-safe
|
12
|
+
* Pure ruby
|
13
|
+
|
14
|
+
## INSTALL:
|
15
|
+
|
16
|
+
gem install gene_pool
|
17
|
+
|
18
|
+
## EXAMPLE USAGE:
|
19
|
+
|
20
|
+
class MyClient
|
21
|
+
# Print a logger warning if it requires more than 0.25 seconds to acquire a connection.
|
22
|
+
# Close and reopen the connection if it hasn't been used for 10 seconds.
|
23
|
+
@@gene_pool = GenePool.new(:name => 'MyClient',
|
24
|
+
:pool_size => 10,
|
25
|
+
:warn_timeout => 0.25,
|
26
|
+
:idle_timeout => 10,
|
27
|
+
:logger => Rails.logger,
|
28
|
+
:close_proc => :close) do
|
29
|
+
TCPSocket.new('myserver', 4321)
|
30
|
+
end
|
31
|
+
|
32
|
+
def send_message
|
33
|
+
@@gene_pool.with_connection do |socket|
|
34
|
+
begin
|
35
|
+
# use socket here
|
36
|
+
rescue Exception => e
|
37
|
+
# If the socket gets closed, remove it from the pool
|
38
|
+
@@gene_pool.remove(socket)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Equivalent to send_message above
|
44
|
+
def send_message_auto_remove
|
45
|
+
# On exception, close and reopen socket and perform retry
|
46
|
+
@@gene_pool.with_connection_auto_remove do |socket|
|
47
|
+
# use socket here,
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def send_message_auto_retry
|
52
|
+
# On exception, close and reopen socket and perform retry
|
53
|
+
@@gene_pool.with_connection_auto_retry do |socket|
|
54
|
+
# use socket here,
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
## Copyright
|
60
|
+
|
61
|
+
Copyright (c) 2010-2012 Brad Pardee. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -1,16 +1,34 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
require 'rubygems'
|
2
|
-
require 'rake'
|
3
|
-
|
4
3
|
begin
|
5
|
-
require '
|
6
|
-
Jeweler::Tasks.new do |gemspec|
|
7
|
-
gemspec.name = "gene_pool"
|
8
|
-
gemspec.summary = "Generic pooling library for creating a connection pool"
|
9
|
-
gemspec.description = "Generic pooling library for creating a connection pool"
|
10
|
-
gemspec.email = "bradpardee@gmail.com"
|
11
|
-
gemspec.homepage = "http://github.com/bpardee/gene_pool"
|
12
|
-
gemspec.authors = ["Brad Pardee"]
|
13
|
-
end
|
4
|
+
require 'bundler/setup'
|
14
5
|
rescue LoadError
|
15
|
-
puts
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rake'
|
10
|
+
require 'rdoc/task'
|
11
|
+
require 'rake/testtask'
|
12
|
+
require 'rake/clean'
|
13
|
+
|
14
|
+
desc "Build gem"
|
15
|
+
task :gem do |t|
|
16
|
+
system 'gem build gene_pool.gemspec'
|
17
|
+
end
|
18
|
+
|
19
|
+
Rake::TestTask.new(:test) do |t|
|
20
|
+
t.libs << 'lib'
|
21
|
+
t.libs << 'test'
|
22
|
+
t.pattern = 'test/**/*_test.rb'
|
23
|
+
t.verbose = false
|
24
|
+
end
|
25
|
+
|
26
|
+
task :default => :test
|
27
|
+
|
28
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
29
|
+
rdoc.rdoc_dir = 'rdoc'
|
30
|
+
rdoc.title = 'GenePool'
|
31
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
32
|
+
rdoc.rdoc_files.include('README.md')
|
33
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
16
34
|
end
|
data/lib/gene_pool.rb
CHANGED
@@ -1,21 +1,40 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
1
3
|
# Generic connection pool class
|
2
4
|
class GenePool
|
3
5
|
|
4
|
-
|
6
|
+
attr_accessor :name, :pool_size, :warn_timeout, :logger
|
5
7
|
|
8
|
+
# Creates a gene_pool. The passed block will be used to initialize a single instance of
|
9
|
+
# the item being pooled (i.e., socket connection or whatever)
|
10
|
+
# options -
|
11
|
+
# name - The name used in logging messages
|
12
|
+
# pool_size - The maximum number of instances that will be created (Defaults to 1).
|
13
|
+
# warn_timeout - Displays an error message if a checkout takes longer that the given time (used to give hints to increase the pool size)
|
14
|
+
# idle_timeout - If set, the connection will be renewed if it hasn't been used in this amount of time (seconds)
|
15
|
+
# logger - The logger used for log messages, defaults to STDERR.
|
16
|
+
# close_proc - The process or method used to close a pooled instance when it is removed.
|
17
|
+
# Defaults to :close. Set to nil for no-op or a symbol for a method or a proc that takes an argument for the instance.
|
6
18
|
def initialize(options={}, &connect_block)
|
7
19
|
@connect_block = connect_block
|
8
20
|
|
9
21
|
@name = options[:name] || 'GenePool'
|
10
22
|
@pool_size = options[:pool_size] || 1
|
11
23
|
@warn_timeout = options[:warn_timeout] || 5.0
|
24
|
+
@idle_timeout = options[:idle_timeout]
|
12
25
|
@logger = options[:logger]
|
26
|
+
@close_proc = options[:close_proc] || :close
|
27
|
+
|
28
|
+
unless @logger
|
29
|
+
@logger = Logger.new(STDERR)
|
30
|
+
@logger.level = Logger::INFO
|
31
|
+
end
|
13
32
|
|
14
33
|
# Mutex for synchronizing pool access
|
15
34
|
@mutex = Mutex.new
|
16
35
|
|
17
36
|
# Condition variable for waiting for an available connection
|
18
|
-
@
|
37
|
+
@condition = ConditionVariable.new
|
19
38
|
|
20
39
|
@connections = []
|
21
40
|
@checked_out = []
|
@@ -24,6 +43,26 @@ class GenePool
|
|
24
43
|
@with_map = {}
|
25
44
|
end
|
26
45
|
|
46
|
+
def size
|
47
|
+
@mutex.synchronize do
|
48
|
+
return @connections.size
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def pool_size=(size)
|
53
|
+
@mutex.synchronize do
|
54
|
+
return if @pool_size == size
|
55
|
+
@pool_size = size
|
56
|
+
if @pool_size < @connections.size
|
57
|
+
old_connections = (@connections - @checked_out).last(@connections.size - @pool_size)
|
58
|
+
old_connections.each do |connection|
|
59
|
+
remove_and_close(connection)
|
60
|
+
@logger.info "#{@name}: Connection #{connection}(#{connection.object_id}) has been removed due to pool size reduction"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
27
66
|
# Check out a connection from the pool, creating it if necessary.
|
28
67
|
def checkout
|
29
68
|
start_time = Time.now
|
@@ -31,6 +70,7 @@ class GenePool
|
|
31
70
|
reserved_connection_placeholder = Thread.current
|
32
71
|
begin
|
33
72
|
@mutex.synchronize do
|
73
|
+
raise "Can't perform checkout, #{@name} has been closed" if @pool_size == 0
|
34
74
|
until connection do
|
35
75
|
if @checked_out.size < @connections.size
|
36
76
|
connection = (@connections - @checked_out).first
|
@@ -40,25 +80,27 @@ class GenePool
|
|
40
80
|
connection = reserved_connection_placeholder
|
41
81
|
@connections << connection
|
42
82
|
@checked_out << connection
|
43
|
-
@logger.debug "#{@name}: Created connection ##{@connections.size} #{connection}
|
83
|
+
@logger.debug {"#{@name}: Created connection ##{@connections.size} #{connection}(#{connection.object_id}) for #{name}"}
|
44
84
|
else
|
45
|
-
@logger.info "#{@name}: Waiting for an available connection, all #{@pool_size} connections are checked out."
|
46
|
-
@
|
85
|
+
@logger.info "#{@name}: Waiting for an available connection, all #{@pool_size} connections are checked out."
|
86
|
+
@condition.wait(@mutex)
|
47
87
|
end
|
48
88
|
end
|
49
89
|
end
|
50
90
|
ensure
|
51
91
|
delta = Time.now - start_time
|
52
|
-
if
|
92
|
+
if delta > @warn_timeout
|
53
93
|
@logger.warn "#{@name}: It took #{delta} seconds to obtain a connection. Consider raising the pool size which is " +
|
54
94
|
"currently set to #{@pool_size}."
|
55
95
|
end
|
56
96
|
end
|
57
97
|
if connection == reserved_connection_placeholder
|
58
98
|
connection = renew(reserved_connection_placeholder)
|
99
|
+
elsif @idle_timeout && (Time.now - connection._last_used) >= @idle_timeout
|
100
|
+
connection = renew(connection)
|
59
101
|
end
|
60
102
|
|
61
|
-
@logger.debug "#{@name}: Checkout connection #{connection.object_id} self=#{
|
103
|
+
@logger.debug {"#{@name}: Checkout connection #{connection}(#{connection.object_id}) self=#{self}"}
|
62
104
|
return connection
|
63
105
|
end
|
64
106
|
|
@@ -66,12 +108,24 @@ class GenePool
|
|
66
108
|
def checkin(connection)
|
67
109
|
@mutex.synchronize do
|
68
110
|
@checked_out.delete(connection)
|
69
|
-
@
|
111
|
+
if @pool_size < @connections.size
|
112
|
+
remove_and_close(connection)
|
113
|
+
@logger.info "#{@name}: Checkin connection #{connection}(#{connection.object_id}) has been removed due to pool size reduction"
|
114
|
+
else
|
115
|
+
connection._last_used = Time.now
|
116
|
+
@condition.signal
|
117
|
+
end
|
70
118
|
end
|
71
|
-
@logger.debug "#{@name}: Checkin connection #{connection.object_id} self=#{
|
119
|
+
@logger.debug {"#{@name}: Checkin connection #{connection}(#{connection.object_id}) self=#{self}"}
|
72
120
|
end
|
73
121
|
|
74
122
|
# Create a scope for checking out a connection
|
123
|
+
# The client should handle cleanup on exception which should be something similar to the following:
|
124
|
+
# rescue Exception => e
|
125
|
+
# @gene_pool.remove(connection)
|
126
|
+
# raise
|
127
|
+
# end
|
128
|
+
# Note that with_connection_auto_remove automatically does this
|
75
129
|
def with_connection
|
76
130
|
connection = checkout
|
77
131
|
@mutex.synchronize do
|
@@ -87,16 +141,26 @@ class GenePool
|
|
87
141
|
checkin(connection)
|
88
142
|
end
|
89
143
|
end
|
90
|
-
|
144
|
+
|
145
|
+
# Create a scope for checking out a connection while automatically removing this connection on exception
|
146
|
+
def with_connection_auto_remove
|
147
|
+
with_connection do |connection|
|
148
|
+
begin
|
149
|
+
yield connection
|
150
|
+
rescue Exception => e
|
151
|
+
remove(connection)
|
152
|
+
raise
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
|
91
158
|
# Create a scope for checking out a connection while automatically retrying on exception
|
92
|
-
def with_connection_auto_retry
|
159
|
+
def with_connection_auto_retry
|
93
160
|
with_connection do |connection|
|
94
161
|
begin
|
95
162
|
yield connection
|
96
163
|
rescue Exception => e
|
97
|
-
if close_on_error
|
98
|
-
connection.close rescue nil
|
99
|
-
end
|
100
164
|
if e.kind_of?(Timeout::Error) || e.message =~ /expired/
|
101
165
|
remove(connection)
|
102
166
|
raise
|
@@ -105,9 +169,6 @@ class GenePool
|
|
105
169
|
begin
|
106
170
|
yield connection
|
107
171
|
rescue Exception => e
|
108
|
-
if close_on_error
|
109
|
-
connection.close rescue nil
|
110
|
-
end
|
111
172
|
remove(connection)
|
112
173
|
raise
|
113
174
|
end
|
@@ -120,9 +181,10 @@ class GenePool
|
|
120
181
|
@mutex.synchronize do
|
121
182
|
@connections.delete(connection)
|
122
183
|
@checked_out.delete(connection)
|
123
|
-
@
|
184
|
+
@condition.signal
|
124
185
|
end
|
125
|
-
|
186
|
+
close_connection(connection)
|
187
|
+
@logger.debug {"#{@name}: Removed connection #{connection}(#{connection.object_id}) self=#{self}"}
|
126
188
|
end
|
127
189
|
|
128
190
|
# If a connection needs to be renewed for some reason, reassign it here
|
@@ -134,29 +196,56 @@ class GenePool
|
|
134
196
|
remove old_connection
|
135
197
|
raise
|
136
198
|
end
|
199
|
+
class << new_connection
|
200
|
+
attr_accessor :_last_used
|
201
|
+
end
|
137
202
|
@mutex.synchronize do
|
138
203
|
index = @checked_out.index(old_connection)
|
139
204
|
raise Error.new("Can't reassign non-checked out connection for #{@name}") unless index
|
205
|
+
close_connection(old_connection)
|
140
206
|
@checked_out[index] = new_connection
|
141
207
|
@connections[@connections.index(old_connection)] = new_connection
|
142
208
|
# If this is part of a with_connection block, then track our new connection
|
143
|
-
with_key = @with_map.
|
209
|
+
with_key = @with_map.key(old_connection)
|
144
210
|
@with_map[with_key] = new_connection if with_key
|
145
211
|
end
|
146
|
-
@logger.debug "#{@name}: Renewed connection old=#{old_connection.object_id} new=#{new_connection}
|
212
|
+
@logger.debug {"#{@name}: Renewed connection old=#{old_connection.object_id} new=#{new_connection}(#{new_connection.object_id})"}
|
147
213
|
return new_connection
|
148
214
|
end
|
149
215
|
|
150
|
-
# Perform the given block for each connection
|
216
|
+
# Perform the given block for each connection. Note that close should be used for safely closing all connections
|
151
217
|
def each
|
218
|
+
# TBD: Should this be removed? This should probably only ever be used to allow interrupt of a connection that is checked out?
|
152
219
|
@mutex.synchronize do
|
153
220
|
@connections.each { |connection| yield connection }
|
154
221
|
end
|
155
222
|
end
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
223
|
+
|
224
|
+
def close(timeout=10)
|
225
|
+
self.pool_size = 0
|
226
|
+
start = Time.now
|
227
|
+
while (Time.now - start) < timeout
|
228
|
+
sleep 1
|
229
|
+
@mutex.synchronize do
|
230
|
+
return if @connections.empty?
|
231
|
+
@logger.info "#{@name}: Waiting to close, #{@connections.size} connections are still in use"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
@logger.warn "#{@name}: Timed out while waiting to close, #{@connections.size} connections are still in use"
|
235
|
+
end
|
236
|
+
|
237
|
+
def remove_idle(idle_time=60)
|
238
|
+
@mutex.synchronize do
|
239
|
+
(@connections - @checked_out).each do |idle_connection|
|
240
|
+
if (Time.now - idle_connection._last_used) >= idle_time
|
241
|
+
remove_and_close(idle_connection)
|
242
|
+
@logger.debug {"#{@name}: Removed idle connection=#{idle_connection}(#{idle_connection.object_id})"}
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def to_s
|
160
249
|
conn = chk = with = nil
|
161
250
|
@mutex.synchronize do
|
162
251
|
conn = @connections.map{|c| c.object_id}.join(',')
|
@@ -165,4 +254,29 @@ class GenePool
|
|
165
254
|
end
|
166
255
|
"connections=#{conn} checked_out=#{chk} with_map=#{with}"
|
167
256
|
end
|
257
|
+
|
258
|
+
#######
|
259
|
+
private
|
260
|
+
#######
|
261
|
+
|
262
|
+
def close_connection(connection)
|
263
|
+
return unless @close_proc
|
264
|
+
# Thread is used as a reserved_connection_placeholder so don't close the connection if it's actually a thread
|
265
|
+
return if connection.kind_of?(Thread)
|
266
|
+
if @close_proc.kind_of?(Symbol)
|
267
|
+
connection.send(@close_proc)
|
268
|
+
else
|
269
|
+
@close_proc.call(connection)
|
270
|
+
end
|
271
|
+
rescue NoMethodError
|
272
|
+
@logger.warn "Unable to close, you should explicitly set :close_proc => nil in the gene_pool options"
|
273
|
+
rescue Exception => e
|
274
|
+
@logger.warn "Exception trying to close #{connection}(#{connection.object_id}): #{e.message}\n\t#{e.backtrace.join("\n\t")}"
|
275
|
+
end
|
276
|
+
|
277
|
+
# Clients should have obtained the mutex before calling this!
|
278
|
+
def remove_and_close(connection)
|
279
|
+
@connections.delete(connection)
|
280
|
+
close_connection(connection)
|
281
|
+
end
|
168
282
|
end
|
data/test/gene_pool_test.rb
CHANGED
@@ -48,7 +48,7 @@ class GenePoolTest < Test::Unit::TestCase
|
|
48
48
|
assert_equal 'GenePool', @gene_pool.name
|
49
49
|
assert_equal 1, @gene_pool.pool_size
|
50
50
|
assert_equal 5.0, @gene_pool.warn_timeout
|
51
|
-
|
51
|
+
assert @gene_pool.logger
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -57,15 +57,14 @@ class GenePoolTest < Test::Unit::TestCase
|
|
57
57
|
#@stringio = StringIO.new
|
58
58
|
#@logger = Logger.new($stdout)
|
59
59
|
#@logger = Logger.new(@stringio)
|
60
|
-
@logger = nil
|
61
60
|
# Override sleep in individual tests
|
62
61
|
@sleep = nil
|
63
62
|
counter = 0
|
64
63
|
mutex = Mutex.new
|
65
64
|
@gene_pool = GenePool.new(:name => 'TestGenePool',
|
66
65
|
:pool_size => 10,
|
67
|
-
|
68
|
-
:
|
66
|
+
#:logger => @logger,
|
67
|
+
:warn_timeout => 2.0) do
|
69
68
|
count = nil
|
70
69
|
mutex.synchronize do
|
71
70
|
count = counter += 1
|
@@ -76,9 +75,9 @@ class GenePoolTest < Test::Unit::TestCase
|
|
76
75
|
|
77
76
|
should 'have options set' do
|
78
77
|
assert_equal 'TestGenePool', @gene_pool.name
|
79
|
-
assert_equal 10,
|
78
|
+
assert_equal 10, @gene_pool.pool_size
|
80
79
|
assert_equal 2.0, @gene_pool.warn_timeout
|
81
|
-
assert_same @logger, @gene_pool.logger
|
80
|
+
#assert_same @logger, @gene_pool.logger
|
82
81
|
end
|
83
82
|
|
84
83
|
should 'create 1 connection' do
|
@@ -174,9 +173,9 @@ class GenePoolTest < Test::Unit::TestCase
|
|
174
173
|
# Do another test just to be sure nothings hosed
|
175
174
|
@sleep = nil
|
176
175
|
@gene_pool.with_connection do |conn1|
|
177
|
-
|
176
|
+
assert_equal 1, conn1.count
|
178
177
|
@gene_pool.with_connection do |conn2|
|
179
|
-
|
178
|
+
assert_equal 3, conn2.count
|
180
179
|
end
|
181
180
|
end
|
182
181
|
end
|
@@ -238,27 +237,29 @@ class GenePoolTest < Test::Unit::TestCase
|
|
238
237
|
end
|
239
238
|
|
240
239
|
should 'be able to auto-retry connection' do
|
241
|
-
|
242
|
-
|
243
|
-
conns
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
assert_equal
|
252
|
-
|
253
|
-
i += 1
|
240
|
+
conns = []
|
241
|
+
@gene_pool.with_connection_auto_retry do |conn|
|
242
|
+
conns << conn
|
243
|
+
conn.fail_on(1)
|
244
|
+
assert_equal 1, @gene_pool.connections.size
|
245
|
+
assert_equal 1, @gene_pool.checked_out.size
|
246
|
+
assert_equal 2, conn.count
|
247
|
+
end
|
248
|
+
@gene_pool.with_connection_auto_retry do |conn|
|
249
|
+
conns << conn
|
250
|
+
assert_equal 1, @gene_pool.connections.size
|
251
|
+
assert_equal 1, @gene_pool.checked_out.size
|
254
252
|
end
|
253
|
+
assert conns[0].closed?
|
254
|
+
assert !conns[1].closed?
|
255
|
+
assert_same conns[1], conns[2]
|
255
256
|
assert_equal 1, @gene_pool.connections.size
|
256
257
|
assert_equal 0, @gene_pool.checked_out.size
|
257
258
|
end
|
258
259
|
|
259
260
|
should 'fail with auto-retry on double failure' do
|
260
261
|
e = assert_raises Exception do
|
261
|
-
@gene_pool.with_connection_auto_retry
|
262
|
+
@gene_pool.with_connection_auto_retry do |conn|
|
262
263
|
conn.fail_on(1,2)
|
263
264
|
end
|
264
265
|
end
|
@@ -289,5 +290,52 @@ class GenePoolTest < Test::Unit::TestCase
|
|
289
290
|
assert_equal 1, @gene_pool.connections.size
|
290
291
|
assert_equal 0, @gene_pool.checked_out.size
|
291
292
|
end
|
293
|
+
|
294
|
+
should 'allow cleanup of idle connections' do
|
295
|
+
conn1 = @gene_pool.checkout
|
296
|
+
conn2 = @gene_pool.checkout
|
297
|
+
@gene_pool.checkin(conn1)
|
298
|
+
sleep 2
|
299
|
+
@gene_pool.checkin(conn2)
|
300
|
+
assert_equal 2, @gene_pool.connections.size
|
301
|
+
assert_equal 0, @gene_pool.checked_out.size
|
302
|
+
@gene_pool.remove_idle(1)
|
303
|
+
assert_equal 1, @gene_pool.connections.size
|
304
|
+
assert conn1.closed?
|
305
|
+
assert !conn2.closed?
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
context 'idle timeout' do
|
310
|
+
setup do
|
311
|
+
# Override sleep in individual tests
|
312
|
+
@sleep = nil
|
313
|
+
counter = 0
|
314
|
+
mutex = Mutex.new
|
315
|
+
@gene_pool = GenePool.new(:name => 'TestGenePool',
|
316
|
+
:pool_size => 10,
|
317
|
+
:idle_timeout => 2.0) do
|
318
|
+
count = nil
|
319
|
+
mutex.synchronize do
|
320
|
+
count = counter += 1
|
321
|
+
end
|
322
|
+
DummyConnection.new(count, @sleep)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
should 'create a new connection if we pass the idle timeout' do
|
327
|
+
conn1, conn2, conn3 = nil
|
328
|
+
@gene_pool.with_connection { |conn| conn1 = conn }
|
329
|
+
@gene_pool.with_connection { |conn| conn2 = conn }
|
330
|
+
assert_equal 1, @gene_pool.connections.size
|
331
|
+
sleep 3
|
332
|
+
@gene_pool.with_connection { |conn| conn3 = conn }
|
333
|
+
assert_equal 1, @gene_pool.connections.size
|
334
|
+
assert_same conn1, conn2
|
335
|
+
assert_equal 1, conn1.count
|
336
|
+
assert_equal 2, conn3.count
|
337
|
+
assert conn1.closed?
|
338
|
+
assert !conn3.closed?
|
339
|
+
end
|
292
340
|
end
|
293
341
|
end
|
metadata
CHANGED
@@ -1,71 +1,56 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: gene_pool
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 1
|
7
|
-
- 1
|
8
|
-
- 1
|
9
|
-
version: 1.1.1
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.0
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
12
|
-
|
7
|
+
authors:
|
8
|
+
- Brad Pardee
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
date: 2010-11-18 00:00:00 -05:00
|
18
|
-
default_executable:
|
12
|
+
date: 2012-02-23 00:00:00.000000000Z
|
19
13
|
dependencies: []
|
20
|
-
|
21
14
|
description: Generic pooling library for creating a connection pool
|
22
|
-
email:
|
15
|
+
email:
|
16
|
+
- bradpardee@gmail.com
|
23
17
|
executables: []
|
24
|
-
|
25
18
|
extensions: []
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
- Rakefile
|
36
|
-
- VERSION
|
37
|
-
- gene_pool.gemspec
|
38
|
-
- lib/gene_pool.rb
|
39
|
-
- test/gene_pool_test.rb
|
40
|
-
has_rdoc: true
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/gene_pool.rb
|
22
|
+
- LICENSE.txt
|
23
|
+
- Rakefile
|
24
|
+
- Gemfile
|
25
|
+
- History.md
|
26
|
+
- README.md
|
27
|
+
- test/gene_pool_test.rb
|
41
28
|
homepage: http://github.com/bpardee/gene_pool
|
42
29
|
licenses: []
|
43
|
-
|
44
30
|
post_install_message:
|
45
|
-
rdoc_options:
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
requirements:
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
segments:
|
41
|
+
- 0
|
42
|
+
hash: 4582705740128393740
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
63
49
|
requirements: []
|
64
|
-
|
65
50
|
rubyforge_project:
|
66
|
-
rubygems_version: 1.
|
51
|
+
rubygems_version: 1.8.10
|
67
52
|
signing_key:
|
68
53
|
specification_version: 3
|
69
54
|
summary: Generic pooling library for creating a connection pool
|
70
|
-
test_files:
|
71
|
-
|
55
|
+
test_files:
|
56
|
+
- test/gene_pool_test.rb
|
data/.gitignore
DELETED
data/History.txt
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
=== 1.1.1 / 2010-11-18
|
2
|
-
|
3
|
-
* Bug fixes
|
4
|
-
* In with_connection_auto_retry, add check for e.message =~ /expired/ as JRuby exception won't be a
|
5
|
-
Timeout::Error at this point (http://jira.codehaus.org/browse/JRUBY-5194)
|
6
|
-
|
7
|
-
=== 1.1.0 / 2010-11-11
|
8
|
-
|
9
|
-
* 1 enhancement:
|
10
|
-
* Added with_connection_auto_retry to automatically retry yield block if a non-timeout exception occurs
|
11
|
-
|
12
|
-
=== 1.0.1 / 2010-09-12
|
13
|
-
|
14
|
-
* Bug Fixes
|
15
|
-
* Debug logging was NOT thread-safe
|
16
|
-
|
17
|
-
== 1.0.0 / 2010-09-05
|
18
|
-
|
19
|
-
* 1 major enhancement:
|
20
|
-
* Initial release
|
data/README.rdoc
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
= gene_pool
|
2
|
-
|
3
|
-
* http://github.com/bpardee/gene_pool
|
4
|
-
|
5
|
-
== DESCRIPTION:
|
6
|
-
|
7
|
-
Generic pooling library for connection pools.
|
8
|
-
|
9
|
-
== FEATURES/PROBLEMS:
|
10
|
-
|
11
|
-
* Thread-safe
|
12
|
-
* Pure ruby
|
13
|
-
|
14
|
-
== INSTALL:
|
15
|
-
|
16
|
-
gem install gene_pool
|
17
|
-
|
18
|
-
== EXAMPLE USAGE:
|
19
|
-
|
20
|
-
class MyClient
|
21
|
-
@@gene_pool = GenePool.new(:name => 'MyClient',
|
22
|
-
:pool_size => 10,
|
23
|
-
:warn_timeout => 0.25,
|
24
|
-
:logger => Rails.logger) do
|
25
|
-
TCPSocket.new('myserver', 4321)
|
26
|
-
end
|
27
|
-
|
28
|
-
def send_message
|
29
|
-
@@gene_pool.with_connection do |socket|
|
30
|
-
# use socket here
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def send_message_auto_retry
|
35
|
-
# On exception, close and reopen socket and perform retry
|
36
|
-
@@gene_pool.with_connection_auto_retry do |socket|
|
37
|
-
# use socket here,
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
== Copyright
|
43
|
-
|
44
|
-
Copyright (c) 2010 Brad Pardee. See LICENSE for details.
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
1.1.1
|
data/gene_pool.gemspec
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
-
# -*- encoding: utf-8 -*-
|
5
|
-
|
6
|
-
Gem::Specification.new do |s|
|
7
|
-
s.name = %q{gene_pool}
|
8
|
-
s.version = "1.1.1"
|
9
|
-
|
10
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = ["Brad Pardee"]
|
12
|
-
s.date = %q{2010-11-18}
|
13
|
-
s.description = %q{Generic pooling library for creating a connection pool}
|
14
|
-
s.email = %q{bradpardee@gmail.com}
|
15
|
-
s.extra_rdoc_files = [
|
16
|
-
"LICENSE",
|
17
|
-
"README.rdoc"
|
18
|
-
]
|
19
|
-
s.files = [
|
20
|
-
".gitignore",
|
21
|
-
"History.txt",
|
22
|
-
"LICENSE",
|
23
|
-
"README.rdoc",
|
24
|
-
"Rakefile",
|
25
|
-
"VERSION",
|
26
|
-
"gene_pool.gemspec",
|
27
|
-
"lib/gene_pool.rb",
|
28
|
-
"test/gene_pool_test.rb"
|
29
|
-
]
|
30
|
-
s.homepage = %q{http://github.com/bpardee/gene_pool}
|
31
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
32
|
-
s.require_paths = ["lib"]
|
33
|
-
s.rubygems_version = %q{1.3.6}
|
34
|
-
s.summary = %q{Generic pooling library for creating a connection pool}
|
35
|
-
s.test_files = [
|
36
|
-
"test/gene_pool_test.rb"
|
37
|
-
]
|
38
|
-
|
39
|
-
if s.respond_to? :specification_version then
|
40
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
41
|
-
s.specification_version = 3
|
42
|
-
|
43
|
-
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
44
|
-
else
|
45
|
-
end
|
46
|
-
else
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|