gene_pool 1.0.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/.gitignore +2 -0
- data/History.txt +4 -0
- data/LICENSE +20 -0
- data/README.rdoc +37 -0
- data/Rakefile +16 -0
- data/VERSION +1 -0
- data/gene_pool.gemspec +49 -0
- data/lib/gene_pool.rb +134 -0
- data/test/gene_pool_test.rb +232 -0
- metadata +71 -0
data/.gitignore
ADDED
data/History.txt
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2010 Brad Pardee
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
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
|
+
end
|
|
34
|
+
|
|
35
|
+
== Copyright
|
|
36
|
+
|
|
37
|
+
Copyright (c) 2010 Brad Pardee. See LICENSE for details.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'rake'
|
|
3
|
+
|
|
4
|
+
begin
|
|
5
|
+
require 'jeweler'
|
|
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
|
|
14
|
+
rescue LoadError
|
|
15
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
|
16
|
+
end
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.0.0
|
data/gene_pool.gemspec
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
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.0.0"
|
|
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-09-08}
|
|
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
|
+
|
data/lib/gene_pool.rb
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Generic connection pool class
|
|
2
|
+
class GenePool
|
|
3
|
+
|
|
4
|
+
attr_reader :name, :pool_size, :warn_timeout, :logger
|
|
5
|
+
|
|
6
|
+
def initialize(options={}, &connect_block)
|
|
7
|
+
@connect_block = connect_block
|
|
8
|
+
|
|
9
|
+
@name = options[:name] || 'GenePool'
|
|
10
|
+
@pool_size = options[:pool_size] || 1
|
|
11
|
+
@warn_timeout = options[:warn_timeout] || 5.0
|
|
12
|
+
@logger = options[:logger]
|
|
13
|
+
|
|
14
|
+
# Mutex for synchronizing pool access
|
|
15
|
+
@mutex = Mutex.new
|
|
16
|
+
|
|
17
|
+
# Condition variable for waiting for an available connection
|
|
18
|
+
@queue = ConditionVariable.new
|
|
19
|
+
|
|
20
|
+
@connections = []
|
|
21
|
+
@checked_out = []
|
|
22
|
+
# Map the original connections object_id within the with_connection method to the final connection.
|
|
23
|
+
# This could change if the connection is renew'ed.
|
|
24
|
+
@with_map = {}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Check out a connection from the pool, creating it if necessary.
|
|
28
|
+
def checkout
|
|
29
|
+
start_time = Time.now
|
|
30
|
+
connection = nil
|
|
31
|
+
reserved_connection_placeholder = Thread.current
|
|
32
|
+
begin
|
|
33
|
+
@mutex.synchronize do
|
|
34
|
+
until connection do
|
|
35
|
+
if @checked_out.size < @connections.size
|
|
36
|
+
connection = (@connections - @checked_out).first
|
|
37
|
+
@checked_out << connection
|
|
38
|
+
elsif @connections.size < @pool_size
|
|
39
|
+
# Perform the actual connection outside the mutex
|
|
40
|
+
connection = reserved_connection_placeholder
|
|
41
|
+
@connections << connection
|
|
42
|
+
@checked_out << connection
|
|
43
|
+
@logger.debug "#{@name}: Created connection ##{@connections.size} #{connection}:#{connection.object_id} for #{name}" if @logger && @logger.debug?
|
|
44
|
+
else
|
|
45
|
+
@logger.info "#{@name}: Waiting for an available connection, all #{@pool_size} connections are checked out." if @logger
|
|
46
|
+
@queue.wait(@mutex)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
ensure
|
|
51
|
+
delta = Time.now - start_time
|
|
52
|
+
if @logger && delta > @warn_timeout
|
|
53
|
+
@logger.warn "#{@name}: It took #{delta} seconds to obtain a connection. Consider raising the pool size which is " +
|
|
54
|
+
"currently set to #{@pool_size}."
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
if connection == reserved_connection_placeholder
|
|
58
|
+
connection = renew(reserved_connection_placeholder)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
@logger.debug "#{@name}: Checkout connection #{connection.object_id} self=#{self}" if @logger && @logger.debug?
|
|
62
|
+
return connection
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Return a connection to the pool.
|
|
66
|
+
def checkin(connection)
|
|
67
|
+
@mutex.synchronize do
|
|
68
|
+
@checked_out.delete(connection)
|
|
69
|
+
@queue.signal
|
|
70
|
+
end
|
|
71
|
+
@logger.debug "#{@name}: Checkin connection #{connection.object_id} self=#{self}" if @logger && @logger.debug?
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Create a scope for checking out a connection
|
|
75
|
+
def with_connection
|
|
76
|
+
connection = checkout
|
|
77
|
+
@mutex.synchronize do
|
|
78
|
+
@with_map[connection.object_id] = connection
|
|
79
|
+
end
|
|
80
|
+
begin
|
|
81
|
+
yield connection
|
|
82
|
+
ensure
|
|
83
|
+
@mutex.synchronize do
|
|
84
|
+
# Update connection for any renew's that have occurred
|
|
85
|
+
connection = @with_map.delete(connection.object_id)
|
|
86
|
+
end
|
|
87
|
+
checkin(connection)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Remove an existing connection from the pool
|
|
92
|
+
def remove(connection)
|
|
93
|
+
@mutex.synchronize do
|
|
94
|
+
@connections.delete(connection)
|
|
95
|
+
@checked_out.delete(connection)
|
|
96
|
+
@queue.signal
|
|
97
|
+
end
|
|
98
|
+
@logger.debug "#{@name}: Removed connection #{connection.object_id} self=#{self}" if @logger && @logger.debug?
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# If a connection needs to be renewed for some reason, reassign it here
|
|
102
|
+
def renew(old_connection)
|
|
103
|
+
new_connection =
|
|
104
|
+
begin
|
|
105
|
+
@connect_block.call
|
|
106
|
+
rescue Exception
|
|
107
|
+
remove old_connection
|
|
108
|
+
raise
|
|
109
|
+
end
|
|
110
|
+
@mutex.synchronize do
|
|
111
|
+
index = @checked_out.index(old_connection)
|
|
112
|
+
raise Error.new("Can't reassign non-checked out connection for #{@name}") unless index
|
|
113
|
+
@checked_out[index] = new_connection
|
|
114
|
+
@connections[@connections.index(old_connection)] = new_connection
|
|
115
|
+
# If this is part of a with_connection block, then track our new connection
|
|
116
|
+
with_key = @with_map.index(old_connection)
|
|
117
|
+
@with_map[with_key] = new_connection if with_key
|
|
118
|
+
end
|
|
119
|
+
@logger.debug "#{@name}: Renewed connection old=#{old_connection.object_id} new=#{new_connection}:#{new_connection.object_id}" if @logger && @logger.debug?
|
|
120
|
+
return new_connection
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Perform the given block for each connection, i.e., closing each connection.
|
|
124
|
+
def each
|
|
125
|
+
@connections.each { |connection| yield connection }
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def to_s
|
|
129
|
+
conn = @connections.map{|c| c.object_id}.join(',')
|
|
130
|
+
chk = @checked_out.map{|c| c.object_id}.join(',')
|
|
131
|
+
with = @with_map.keys.map{|k| "#{k}=#{@with_map[k].object_id}"}.join(',')
|
|
132
|
+
"connections=#{conn} checked_out=#{chk} with_map=#{with}"
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
require 'shoulda'
|
|
4
|
+
require 'gene_pool'
|
|
5
|
+
require 'stringio'
|
|
6
|
+
require 'logger'
|
|
7
|
+
require 'timeout'
|
|
8
|
+
|
|
9
|
+
# Increase visibility
|
|
10
|
+
class GenePool
|
|
11
|
+
attr_reader :connections, :checked_out, :with_map
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class DummyConnection
|
|
15
|
+
def initialize(count, sleep_time=nil)
|
|
16
|
+
sleep sleep_time if sleep_time
|
|
17
|
+
@count = count
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_i
|
|
21
|
+
@count
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_s
|
|
25
|
+
@count.to_s
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class GenePoolTest < Test::Unit::TestCase
|
|
31
|
+
|
|
32
|
+
context 'on default setup' do
|
|
33
|
+
setup do
|
|
34
|
+
@gene_pool = GenePool.new { Object.new }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
should 'have default options set' do
|
|
38
|
+
assert_equal 'GenePool', @gene_pool.name
|
|
39
|
+
assert_equal 1, @gene_pool.pool_size
|
|
40
|
+
assert_equal 5.0, @gene_pool.warn_timeout
|
|
41
|
+
assert_nil @gene_pool.logger
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
context '' do
|
|
46
|
+
setup do
|
|
47
|
+
#@stringio = StringIO.new
|
|
48
|
+
#@logger = Logger.new($stdout)
|
|
49
|
+
#@logger = Logger.new(@stringio)
|
|
50
|
+
@logger = nil
|
|
51
|
+
# Override sleep in individual tests
|
|
52
|
+
@sleep = nil
|
|
53
|
+
@timeout = 5
|
|
54
|
+
counter = 0
|
|
55
|
+
mutex = Mutex.new
|
|
56
|
+
@gene_pool = GenePool.new(:name => 'TestGenePool',
|
|
57
|
+
:pool_size => 10,
|
|
58
|
+
:warn_timeout => 2.0,
|
|
59
|
+
:logger => @logger) do
|
|
60
|
+
count = nil
|
|
61
|
+
mutex.synchronize do
|
|
62
|
+
count = counter += 1
|
|
63
|
+
end
|
|
64
|
+
Timeout.timeout(@timeout) do
|
|
65
|
+
DummyConnection.new(count, @sleep)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
should 'have options set' do
|
|
71
|
+
assert_equal 'TestGenePool', @gene_pool.name
|
|
72
|
+
assert_equal 10, @gene_pool.pool_size
|
|
73
|
+
assert_equal 2.0, @gene_pool.warn_timeout
|
|
74
|
+
assert_same @logger, @gene_pool.logger
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
should 'create 1 connection' do
|
|
78
|
+
(1..3).each do |i|
|
|
79
|
+
@gene_pool.with_connection do |conn|
|
|
80
|
+
assert_equal conn.to_i, 1
|
|
81
|
+
assert_equal 1, @gene_pool.connections.size
|
|
82
|
+
assert_equal 1, @gene_pool.checked_out.size
|
|
83
|
+
assert_same conn, @gene_pool.connections[0]
|
|
84
|
+
assert_same conn, @gene_pool.checked_out[0]
|
|
85
|
+
end
|
|
86
|
+
assert_equal 0, @gene_pool.checked_out.size
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
should 'create 2 connections' do
|
|
91
|
+
conn1 = @gene_pool.checkout
|
|
92
|
+
(1..3).each do |i|
|
|
93
|
+
@gene_pool.with_connection do |conn2|
|
|
94
|
+
assert_equal 1, conn1.to_i
|
|
95
|
+
assert_equal 2, conn2.to_i
|
|
96
|
+
assert_equal 2, @gene_pool.connections.size
|
|
97
|
+
assert_equal 2, @gene_pool.checked_out.size
|
|
98
|
+
assert_same conn1, @gene_pool.connections[0]
|
|
99
|
+
assert_same conn1, @gene_pool.checked_out[0]
|
|
100
|
+
assert_same conn2, @gene_pool.connections[1]
|
|
101
|
+
assert_same conn2, @gene_pool.checked_out[1]
|
|
102
|
+
end
|
|
103
|
+
assert_equal 1, @gene_pool.checked_out.size
|
|
104
|
+
end
|
|
105
|
+
@gene_pool.checkin(conn1)
|
|
106
|
+
assert_equal 0, @gene_pool.checked_out.size
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
should 'be able to reset multiple times' do
|
|
110
|
+
@gene_pool.with_connection do |conn1|
|
|
111
|
+
conn2 = @gene_pool.renew(conn1)
|
|
112
|
+
conn3 = @gene_pool.renew(conn2)
|
|
113
|
+
assert_equal 1, conn1.to_i
|
|
114
|
+
assert_equal 2, conn2.to_i
|
|
115
|
+
assert_equal 3, conn3.to_i
|
|
116
|
+
assert_equal 1, @gene_pool.connections.size
|
|
117
|
+
assert_equal 1, @gene_pool.checked_out.size
|
|
118
|
+
end
|
|
119
|
+
assert_equal 1, @gene_pool.connections.size
|
|
120
|
+
assert_equal 0, @gene_pool.checked_out.size
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
should 'be able to remove connection' do
|
|
124
|
+
@gene_pool.with_connection do |conn|
|
|
125
|
+
@gene_pool.remove(conn)
|
|
126
|
+
assert_equal 0, @gene_pool.connections.size
|
|
127
|
+
assert_equal 0, @gene_pool.checked_out.size
|
|
128
|
+
end
|
|
129
|
+
assert_equal 0, @gene_pool.connections.size
|
|
130
|
+
assert_equal 0, @gene_pool.checked_out.size
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
should 'be able to remove multiple connections' do
|
|
134
|
+
@gene_pool.with_connection do |conn1|
|
|
135
|
+
@gene_pool.with_connection do |conn2|
|
|
136
|
+
@gene_pool.with_connection do |conn3|
|
|
137
|
+
@gene_pool.remove(conn1)
|
|
138
|
+
@gene_pool.remove(conn3)
|
|
139
|
+
assert_equal 1, @gene_pool.connections.size
|
|
140
|
+
assert_equal 1, @gene_pool.checked_out.size
|
|
141
|
+
assert_same conn2, @gene_pool.checked_out[0]
|
|
142
|
+
assert_same conn2, @gene_pool.connections[0]
|
|
143
|
+
end
|
|
144
|
+
assert_equal 1, @gene_pool.connections.size
|
|
145
|
+
assert_equal 1, @gene_pool.checked_out.size
|
|
146
|
+
end
|
|
147
|
+
assert_equal 1, @gene_pool.connections.size
|
|
148
|
+
assert_equal 0, @gene_pool.checked_out.size
|
|
149
|
+
end
|
|
150
|
+
assert_equal 1, @gene_pool.connections.size
|
|
151
|
+
assert_equal 0, @gene_pool.checked_out.size
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
should 'handle aborted connection' do
|
|
155
|
+
@gene_pool.with_connection do |conn1|
|
|
156
|
+
@sleep = 2
|
|
157
|
+
@timeout = 1
|
|
158
|
+
begin
|
|
159
|
+
@gene_pool.with_connection { |conn2| }
|
|
160
|
+
flunk "connection should have timed out"
|
|
161
|
+
rescue Timeout::Error => e
|
|
162
|
+
#pass
|
|
163
|
+
end
|
|
164
|
+
assert_equal 1, @gene_pool.connections.size
|
|
165
|
+
assert_equal 1, @gene_pool.checked_out.size
|
|
166
|
+
end
|
|
167
|
+
assert_equal 1, @gene_pool.connections.size
|
|
168
|
+
assert_equal 0, @gene_pool.checked_out.size
|
|
169
|
+
# Do another test just to be sure nothings hosed
|
|
170
|
+
@sleep = nil
|
|
171
|
+
@gene_pool.with_connection do |conn1|
|
|
172
|
+
assert 1, conn1.to_i
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
should 'not allow more than pool_size connections' do
|
|
177
|
+
conns = []
|
|
178
|
+
pool_size = @gene_pool.pool_size
|
|
179
|
+
(1..pool_size).each do |i|
|
|
180
|
+
c = @gene_pool.checkout
|
|
181
|
+
conns << c
|
|
182
|
+
assert_equal i, c.to_i
|
|
183
|
+
assert_equal i, @gene_pool.connections.size
|
|
184
|
+
assert_equal i, @gene_pool.checked_out.size
|
|
185
|
+
assert_equal conns, @gene_pool.connections
|
|
186
|
+
end
|
|
187
|
+
begin
|
|
188
|
+
Timeout.timeout(1) do
|
|
189
|
+
@gene_pool.checkout
|
|
190
|
+
end
|
|
191
|
+
flunk "connection should have timed out"
|
|
192
|
+
rescue Timeout::Error => e
|
|
193
|
+
#pass "successfully timed out connection"
|
|
194
|
+
end
|
|
195
|
+
(1..pool_size).each do |i|
|
|
196
|
+
@gene_pool.checkin(conns[i-1])
|
|
197
|
+
assert_equal pool_size, @gene_pool.connections.size
|
|
198
|
+
assert_equal pool_size-i, @gene_pool.checked_out.size
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
should 'handle thread contention' do
|
|
203
|
+
conns = []
|
|
204
|
+
pool_size = @gene_pool.pool_size
|
|
205
|
+
# Do it with new connections and old connections
|
|
206
|
+
(1..2).each do |n|
|
|
207
|
+
(1..pool_size).each do |i|
|
|
208
|
+
Thread.new do
|
|
209
|
+
c = @gene_pool.checkout
|
|
210
|
+
conns[i-1] = c
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
# Let the threads complete
|
|
214
|
+
sleep 1
|
|
215
|
+
assert_equal pool_size, @gene_pool.connections.size
|
|
216
|
+
assert_equal pool_size, @gene_pool.checked_out.size
|
|
217
|
+
(1..pool_size).each do |i|
|
|
218
|
+
Thread.new do
|
|
219
|
+
@gene_pool.checkin(conns[i-1])
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
sleep 1
|
|
223
|
+
assert_equal pool_size, @gene_pool.connections.size
|
|
224
|
+
assert_equal 0, @gene_pool.checked_out.size
|
|
225
|
+
end
|
|
226
|
+
ival_conns = []
|
|
227
|
+
@gene_pool.each { |conn| ival_conns << conn.to_i }
|
|
228
|
+
ival_conns.sort!
|
|
229
|
+
assert_equal (1..pool_size).to_a, ival_conns
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: gene_pool
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
prerelease: false
|
|
5
|
+
segments:
|
|
6
|
+
- 1
|
|
7
|
+
- 0
|
|
8
|
+
- 0
|
|
9
|
+
version: 1.0.0
|
|
10
|
+
platform: ruby
|
|
11
|
+
authors:
|
|
12
|
+
- Brad Pardee
|
|
13
|
+
autorequire:
|
|
14
|
+
bindir: bin
|
|
15
|
+
cert_chain: []
|
|
16
|
+
|
|
17
|
+
date: 2010-09-08 00:00:00 -04:00
|
|
18
|
+
default_executable:
|
|
19
|
+
dependencies: []
|
|
20
|
+
|
|
21
|
+
description: Generic pooling library for creating a connection pool
|
|
22
|
+
email: bradpardee@gmail.com
|
|
23
|
+
executables: []
|
|
24
|
+
|
|
25
|
+
extensions: []
|
|
26
|
+
|
|
27
|
+
extra_rdoc_files:
|
|
28
|
+
- LICENSE
|
|
29
|
+
- README.rdoc
|
|
30
|
+
files:
|
|
31
|
+
- .gitignore
|
|
32
|
+
- History.txt
|
|
33
|
+
- LICENSE
|
|
34
|
+
- README.rdoc
|
|
35
|
+
- Rakefile
|
|
36
|
+
- VERSION
|
|
37
|
+
- gene_pool.gemspec
|
|
38
|
+
- lib/gene_pool.rb
|
|
39
|
+
- test/gene_pool_test.rb
|
|
40
|
+
has_rdoc: true
|
|
41
|
+
homepage: http://github.com/bpardee/gene_pool
|
|
42
|
+
licenses: []
|
|
43
|
+
|
|
44
|
+
post_install_message:
|
|
45
|
+
rdoc_options:
|
|
46
|
+
- --charset=UTF-8
|
|
47
|
+
require_paths:
|
|
48
|
+
- lib
|
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
segments:
|
|
54
|
+
- 0
|
|
55
|
+
version: "0"
|
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
segments:
|
|
61
|
+
- 0
|
|
62
|
+
version: "0"
|
|
63
|
+
requirements: []
|
|
64
|
+
|
|
65
|
+
rubyforge_project:
|
|
66
|
+
rubygems_version: 1.3.6
|
|
67
|
+
signing_key:
|
|
68
|
+
specification_version: 3
|
|
69
|
+
summary: Generic pooling library for creating a connection pool
|
|
70
|
+
test_files:
|
|
71
|
+
- test/gene_pool_test.rb
|