gene_pool 1.1.1 → 1.2.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.
- 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
|
-
|