activerecord-bogacs 0.5.0 → 0.7.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 +5 -5
- data/.github/workflows/test.yml +82 -0
- data/.travis.yml +32 -34
- data/Gemfile +2 -15
- data/LICENSE.txt +1 -1
- data/README.md +45 -21
- data/Rakefile +8 -6
- data/activerecord-bogacs.gemspec +6 -6
- data/lib/active_record/bogacs/autoload.rb +10 -0
- data/lib/active_record/bogacs/connection_handler.rb +36 -0
- data/lib/active_record/bogacs/default_pool.rb +278 -129
- data/lib/active_record/bogacs/false_pool.rb +95 -73
- data/lib/active_record/bogacs/pool_support.rb +26 -9
- data/lib/active_record/bogacs/railtie.rb +17 -0
- data/lib/active_record/bogacs/reaper.rb +4 -6
- data/lib/active_record/bogacs/shareable_pool.rb +12 -16
- data/lib/active_record/bogacs/thread_safe/synchronized.rb +18 -22
- data/lib/active_record/bogacs/thread_safe.rb +3 -67
- data/lib/active_record/bogacs/validator.rb +21 -26
- data/lib/active_record/bogacs/version.rb +2 -2
- data/lib/active_record/bogacs.rb +7 -54
- data/lib/active_record/connection_adapters/adapter_compat.rb +63 -17
- data/lib/active_record/connection_adapters/pool_class.rb +75 -0
- data/lib/activerecord-bogacs.rb +1 -0
- data/test/active_record/bogacs/false_pool_test.rb +66 -78
- data/test/active_record/bogacs/shareable_pool/connection_pool_test.rb +6 -3
- data/test/active_record/bogacs/shareable_pool/connection_sharing_test.rb +3 -2
- data/test/active_record/bogacs/shareable_pool_helper.rb +1 -1
- data/test/active_record/bogacs/validator_test.rb +22 -28
- data/test/active_record/connection_pool_test_methods.rb +24 -20
- data/test/test_helper.rb +42 -25
- metadata +35 -17
@@ -1,10 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'concurrent/timer_task'
|
4
|
-
rescue LoadError => e
|
5
|
-
warn "activerecord-bogacs' validator feature needs gem 'concurrent-ruby', please install or add it to your Gemfile"
|
6
|
-
raise e
|
7
|
-
end
|
1
|
+
require 'concurrent/executors'
|
2
|
+
require 'concurrent/timer_task'
|
8
3
|
|
9
4
|
require 'active_record/connection_adapters/adapter_compat'
|
10
5
|
require 'active_record/bogacs/thread_safe'
|
@@ -12,13 +7,9 @@ require 'active_record/bogacs/thread_safe'
|
|
12
7
|
module ActiveRecord
|
13
8
|
module Bogacs
|
14
9
|
|
15
|
-
# Every
|
10
|
+
# Every *frequency* seconds, the _validator_ will perform connection validation
|
16
11
|
# on a pool it operates.
|
17
12
|
#
|
18
|
-
# @note Do not use a reaper with the validator as reaping (stale connection detection
|
19
|
-
# and removal) is part of the validation process and will only likely slow things down
|
20
|
-
# as all pool connection updates needs to be synchronized.
|
21
|
-
#
|
22
13
|
# Configure the frequency by setting `:validate_frequency` in your AR configuration.
|
23
14
|
#
|
24
15
|
# We recommend not setting values too low as that would drain the pool's performance
|
@@ -26,11 +17,15 @@ module ActiveRecord
|
|
26
17
|
# checkout - the validator is intended to detect long idle pooled connections "ahead
|
27
18
|
# of time" instead of upon retrieval.
|
28
19
|
#
|
20
|
+
# @note Do not use a reaper with the validator!
|
21
|
+
# Reaping (stale connection detection and removal) is part of the validation
|
22
|
+
# process and will only slow things down as all pool connection updates needs
|
23
|
+
# to be synchronized.
|
29
24
|
class Validator
|
30
25
|
|
31
26
|
attr_reader :pool, :frequency, :timeout
|
32
27
|
|
33
|
-
# Validator.new(
|
28
|
+
# `Validator.new(pool, spec.config[:validate_frequency]).run`
|
34
29
|
# @private
|
35
30
|
def initialize(pool, frequency = 60, timeout = nil)
|
36
31
|
@pool = pool; PoolAdaptor.adapt! pool
|
@@ -81,20 +76,19 @@ module ActiveRecord
|
|
81
76
|
connections = pool.connections.dup
|
82
77
|
connections.map! do |conn|
|
83
78
|
if conn
|
84
|
-
owner = conn.owner
|
85
|
-
|
86
|
-
|
79
|
+
if owner = conn.owner
|
80
|
+
if owner.alive?
|
81
|
+
nil # owner.alive? ... do not touch
|
82
|
+
else # stale-conn (reaping)
|
87
83
|
pool.remove conn # remove is synchronized
|
88
84
|
conn.disconnect! rescue nil
|
89
85
|
nil
|
90
|
-
elsif ! owner # NOTE: this is likely a nasty bug
|
91
|
-
logger && logger.warn("[validator] found in-use connection ##{conn.object_id} without owner - removing from pool")
|
92
|
-
pool.remove_without_owner conn # synchronized
|
93
|
-
conn.disconnect! rescue nil
|
94
|
-
nil
|
95
|
-
else
|
96
|
-
nil # owner.alive? ... do not touch
|
97
86
|
end
|
87
|
+
elsif conn.in_use? # no owner? (likely a nasty bug)
|
88
|
+
logger && logger.warn("[validator] found in-use connection ##{conn.object_id} without owner - removing from pool")
|
89
|
+
pool.remove_without_owner conn # synchronized
|
90
|
+
conn.disconnect! rescue nil
|
91
|
+
nil
|
98
92
|
else
|
99
93
|
conn # conn not in-use - candidate for validation
|
100
94
|
end
|
@@ -116,7 +110,7 @@ module ActiveRecord
|
|
116
110
|
logger && logger.info("[validator] connection ##{conn.object_id} failed to validate: #{e.inspect}")
|
117
111
|
end
|
118
112
|
|
119
|
-
# TODO support
|
113
|
+
# TODO support seconds_idle - only validate if certain amount since use passed
|
120
114
|
|
121
115
|
logger && logger.debug("[validator] found non-active connection ##{conn.object_id} - removing from pool")
|
122
116
|
pool.remove_without_owner conn # not active - remove
|
@@ -170,7 +164,8 @@ module ActiveRecord
|
|
170
164
|
|
171
165
|
def release_without_owner(conn)
|
172
166
|
if owner_id = cached_conn_owner_id(conn)
|
173
|
-
thread_cached_conns.delete owner_id
|
167
|
+
thread_cached_conns.delete owner_id
|
168
|
+
return true
|
174
169
|
end
|
175
170
|
end
|
176
171
|
|
@@ -179,4 +174,4 @@ module ActiveRecord
|
|
179
174
|
end
|
180
175
|
|
181
176
|
end
|
182
|
-
end
|
177
|
+
end
|
data/lib/active_record/bogacs.rb
CHANGED
@@ -1,57 +1,10 @@
|
|
1
|
-
require 'active_record/bogacs/version'
|
2
|
-
|
3
|
-
require 'active_record'
|
4
|
-
require 'active_record/version'
|
5
|
-
require 'active_record/connection_adapters/abstract/connection_pool'
|
6
|
-
|
7
|
-
module ActiveRecord
|
8
|
-
module Bogacs
|
9
|
-
autoload :DefaultPool, 'active_record/bogacs/default_pool'
|
10
|
-
autoload :FalsePool, 'active_record/bogacs/false_pool'
|
11
|
-
autoload :ShareablePool, 'active_record/bogacs/shareable_pool'
|
12
|
-
autoload :Reaper, 'active_record/bogacs/reaper'
|
13
|
-
autoload :Validator, 'active_record/bogacs/validator'
|
14
|
-
end
|
15
|
-
autoload :SharedConnection, 'active_record/shared_connection'
|
16
|
-
end
|
17
|
-
|
18
|
-
# NOTE: needs explicit configuration - before connection gets established e.g.
|
19
|
-
#
|
20
|
-
# klass = ActiveRecord::Bogacs::FalsePool
|
21
|
-
# ActiveRecord::ConnectionAdapters::ConnectionHandler.connection_pool_class = klass
|
22
|
-
#
|
23
|
-
module ActiveRecord
|
24
|
-
module ConnectionAdapters
|
25
|
-
# @private there's no other way to change the pool class to use but to patch :(
|
26
|
-
ConnectionHandler.class_eval do
|
27
|
-
|
28
|
-
@@connection_pool_class = ConnectionAdapters::ConnectionPool
|
29
|
-
|
30
|
-
def connection_pool_class; @@connection_pool_class end
|
31
|
-
def self.connection_pool_class=(klass); @@connection_pool_class = klass end
|
32
|
-
|
33
|
-
if ActiveRecord::VERSION::MAJOR > 3 # 4.x
|
34
1
|
|
35
|
-
|
36
|
-
|
37
|
-
owner_to_pool[owner.name] = connection_pool_class.new(spec)
|
38
|
-
end
|
39
|
-
|
40
|
-
elsif ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 2
|
41
|
-
|
42
|
-
def establish_connection(name, spec)
|
43
|
-
@class_to_pool[name] =
|
44
|
-
( @connection_pools[spec] ||= connection_pool_class.new(spec) )
|
45
|
-
end
|
46
|
-
|
47
|
-
else # 2.3/3.0/3.1
|
48
|
-
|
49
|
-
def establish_connection(name, spec)
|
50
|
-
@connection_pools[name] = connection_pool_class.new(spec)
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
2
|
+
require 'active_record/bogacs/version'
|
3
|
+
require 'active_record/bogacs/autoload'
|
54
4
|
|
55
|
-
|
56
|
-
|
5
|
+
if defined?(Rails::Railtie)
|
6
|
+
require 'active_record/bogacs/railtie'
|
7
|
+
else
|
8
|
+
require 'active_record'
|
9
|
+
require 'active_record/connection_adapters/pool_class'
|
57
10
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'active_record/connection_adapters/abstract_adapter'
|
2
|
+
require 'concurrent/utility/monotonic_time.rb'
|
2
3
|
|
3
4
|
module ActiveRecord
|
4
5
|
module ConnectionAdapters
|
@@ -8,38 +9,59 @@ module ActiveRecord
|
|
8
9
|
|
9
10
|
if method_defined? :owner # >= 4.2
|
10
11
|
|
11
|
-
|
12
|
+
if ActiveRecord::VERSION::STRING > '5.2'
|
12
13
|
|
13
|
-
|
14
|
+
# THIS IS OUR COMPATIBILITY BASE-LINE
|
14
15
|
|
15
|
-
|
16
|
+
elsif ActiveRecord::VERSION::MAJOR > 4
|
17
|
+
|
18
|
+
# this method must only be called while holding connection pool's mutex
|
16
19
|
def lease
|
17
20
|
if in_use?
|
18
|
-
msg =
|
21
|
+
msg = "Cannot lease connection, ".dup
|
19
22
|
if @owner == Thread.current
|
20
|
-
msg
|
23
|
+
msg << "it is already leased by the current thread."
|
21
24
|
else
|
22
|
-
msg
|
25
|
+
msg << "it is already in use by a different thread: #{@owner}. " \
|
26
|
+
"Current thread: #{Thread.current}."
|
23
27
|
end
|
24
28
|
raise ActiveRecordError, msg
|
25
29
|
end
|
26
30
|
|
27
|
-
@owner = Thread.current
|
31
|
+
@owner = Thread.current
|
28
32
|
end
|
29
33
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
def lease
|
34
|
+
# this method must only be called while holding connection pool's mutex
|
35
|
+
# @private AR 5.2
|
36
|
+
def expire
|
34
37
|
if in_use?
|
35
|
-
if @owner
|
36
|
-
|
38
|
+
if @owner != Thread.current
|
39
|
+
raise ActiveRecordError, "Cannot expire connection, " \
|
40
|
+
"it is owned by a different thread: #{@owner}. " \
|
41
|
+
"Current thread: #{Thread.current}."
|
37
42
|
end
|
43
|
+
|
44
|
+
@idle_since = ::Concurrent.monotonic_time
|
45
|
+
@owner = nil
|
38
46
|
else
|
39
|
-
|
47
|
+
raise ActiveRecordError, "Cannot expire connection, it is not currently leased."
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
else
|
52
|
+
|
53
|
+
# @private removed synchronization
|
54
|
+
def lease
|
55
|
+
unless in_use?
|
56
|
+
@owner = Thread.current
|
40
57
|
end
|
41
58
|
end
|
42
59
|
|
60
|
+
# @private added @idle_since
|
61
|
+
def expire
|
62
|
+
@owner = nil; @idle_since = ::Concurrent.monotonic_time
|
63
|
+
end
|
64
|
+
|
43
65
|
end
|
44
66
|
|
45
67
|
else
|
@@ -69,7 +91,7 @@ module ActiveRecord
|
|
69
91
|
end
|
70
92
|
|
71
93
|
def expire
|
72
|
-
@in_use = false; @owner = nil
|
94
|
+
@in_use = false; @owner = nil; @idle_since = ::Concurrent.monotonic_time
|
73
95
|
end
|
74
96
|
|
75
97
|
else
|
@@ -83,13 +105,37 @@ module ActiveRecord
|
|
83
105
|
end
|
84
106
|
|
85
107
|
def expire
|
86
|
-
@owner = nil
|
108
|
+
@owner = nil; @idle_since = ::Concurrent.monotonic_time
|
87
109
|
end
|
88
110
|
|
89
111
|
end
|
90
112
|
|
91
113
|
end
|
92
114
|
|
115
|
+
# this method must only be called while holding connection pool's mutex (and a desire for segfaults)
|
116
|
+
def steal! # :nodoc:
|
117
|
+
if in_use?
|
118
|
+
if @owner != Thread.current
|
119
|
+
pool.send :release, self, @owner # release exists in both default/false pool
|
120
|
+
|
121
|
+
@owner = Thread.current
|
122
|
+
end
|
123
|
+
else
|
124
|
+
raise ActiveRecordError, "Cannot steal connection, it is not currently leased."
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def discard!
|
129
|
+
# no-op
|
130
|
+
end unless method_defined? :discard! # >= 5.2
|
131
|
+
|
132
|
+
# Seconds since this connection was returned to the pool
|
133
|
+
def seconds_idle # :nodoc:
|
134
|
+
return 0 if in_use?
|
135
|
+
time = ::Concurrent.monotonic_time
|
136
|
+
time - ( @idle_since || time )
|
137
|
+
end unless method_defined? :seconds_idle # >= 5.2
|
138
|
+
|
93
139
|
end
|
94
140
|
end
|
95
|
-
end
|
141
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'active_record/version'
|
3
|
+
require 'active_record/connection_adapters/abstract/connection_pool'
|
4
|
+
|
5
|
+
# NOTE: needs explicit configuration - before connection gets established e.g.
|
6
|
+
#
|
7
|
+
# klass = ActiveRecord::Bogacs::FalsePool
|
8
|
+
# ActiveRecord::ConnectionAdapters::ConnectionHandler.connection_pool_class = klass
|
9
|
+
#
|
10
|
+
module ActiveRecord
|
11
|
+
module ConnectionAdapters
|
12
|
+
# @private there's no other way to change the pool class to use but to patch :(
|
13
|
+
class ConnectionHandler
|
14
|
+
|
15
|
+
@@connection_pool_class = ConnectionAdapters::ConnectionPool
|
16
|
+
|
17
|
+
def connection_pool_class; @@connection_pool_class end
|
18
|
+
def self.connection_pool_class=(klass); @@connection_pool_class = klass end
|
19
|
+
|
20
|
+
if ActiveRecord::VERSION::MAJOR > 4 && # 5.1 - 5.2
|
21
|
+
!(ActiveRecord::VERSION::MAJOR == 5 && ActiveRecord::VERSION::MINOR == 0)
|
22
|
+
|
23
|
+
def establish_connection(config)
|
24
|
+
resolver = ConnectionSpecification::Resolver.new(Base.configurations)
|
25
|
+
spec = resolver.spec(config)
|
26
|
+
|
27
|
+
remove_connection(spec.name)
|
28
|
+
|
29
|
+
message_bus = ActiveSupport::Notifications.instrumenter
|
30
|
+
payload = {
|
31
|
+
connection_id: object_id
|
32
|
+
}
|
33
|
+
if spec
|
34
|
+
payload[:spec_name] = spec.name
|
35
|
+
payload[:config] = spec.config
|
36
|
+
end
|
37
|
+
|
38
|
+
message_bus.instrument("!connection.active_record", payload) do
|
39
|
+
owner_to_pool[spec.name] = connection_pool_class.new(spec) # changed
|
40
|
+
end
|
41
|
+
|
42
|
+
owner_to_pool[spec.name]
|
43
|
+
end
|
44
|
+
|
45
|
+
elsif ActiveRecord::VERSION::MAJOR == 5 && ActiveRecord::VERSION::MINOR == 0
|
46
|
+
|
47
|
+
def establish_connection(spec)
|
48
|
+
owner_to_pool[spec.name] = connection_pool_class.new(spec)
|
49
|
+
end
|
50
|
+
|
51
|
+
elsif ActiveRecord::VERSION::MAJOR > 3 # 4.x
|
52
|
+
|
53
|
+
def establish_connection(owner, spec)
|
54
|
+
@class_to_pool.clear
|
55
|
+
owner_to_pool[owner.name] = connection_pool_class.new(spec)
|
56
|
+
end
|
57
|
+
|
58
|
+
elsif ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 2
|
59
|
+
|
60
|
+
def establish_connection(name, spec)
|
61
|
+
@class_to_pool[name] =
|
62
|
+
( @connection_pools[spec] ||= connection_pool_class.new(spec) )
|
63
|
+
end
|
64
|
+
|
65
|
+
else # 2.3/3.0/3.1
|
66
|
+
|
67
|
+
def establish_connection(name, spec)
|
68
|
+
@connection_pools[name] = connection_pool_class.new(spec)
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'active_record/bogacs' # auto-loading with gem '...' declarations
|
@@ -100,6 +100,20 @@ module ActiveRecord
|
|
100
100
|
assert ActiveRecord::Base.connection.exec_query('SELECT 42')
|
101
101
|
end
|
102
102
|
|
103
|
+
# @override
|
104
|
+
def test_checkout_after_close
|
105
|
+
connection = pool.connection
|
106
|
+
assert connection.in_use?
|
107
|
+
assert_equal connection.object_id, pool.connection.object_id
|
108
|
+
|
109
|
+
connection.close # pool.checkin conn
|
110
|
+
assert ! connection.in_use?
|
111
|
+
|
112
|
+
# NOTE: we do not care for connection re-use - it's okay to instantiate a new one
|
113
|
+
#assert_equal connection.object_id, pool.connection.object_id
|
114
|
+
assert pool.connection.in_use?
|
115
|
+
end
|
116
|
+
|
103
117
|
# @override
|
104
118
|
def test_remove_connection
|
105
119
|
conn = pool.checkout
|
@@ -115,12 +129,13 @@ module ActiveRecord
|
|
115
129
|
|
116
130
|
# @override
|
117
131
|
def test_full_pool_exception
|
132
|
+
ActiveRecord::Base.connection_pool.disconnect! # start clean - with no connections
|
118
133
|
# ~ pool_size.times { pool.checkout }
|
119
134
|
threads_ready = Queue.new; threads_block = Atomic.new(0); threads = []
|
120
135
|
max_pool_size.times do |i|
|
121
136
|
threads << Thread.new do
|
122
137
|
begin
|
123
|
-
conn = ActiveRecord::Base.connection
|
138
|
+
conn = ActiveRecord::Base.connection.tap { |conn| conn.tables }
|
124
139
|
threads_block.update { |v| v + 1 }
|
125
140
|
threads_ready << i
|
126
141
|
while threads_block.value != -1 # await
|
@@ -135,8 +150,26 @@ module ActiveRecord
|
|
135
150
|
end
|
136
151
|
max_pool_size.times { threads_ready.pop } # awaits
|
137
152
|
|
138
|
-
|
139
|
-
|
153
|
+
assert_equal max_pool_size, ActiveRecord::Base.connection_pool.connections.size
|
154
|
+
|
155
|
+
threads.each { |thread| assert thread.alive? }
|
156
|
+
|
157
|
+
#puts "data_source.active: #{data_source.getActive} - #{data_source.getNumActive}"
|
158
|
+
|
159
|
+
begin
|
160
|
+
# NOTE: in AR 4.x and before AR::Base.connection was enough
|
161
|
+
# but due the lazy nature of connection init in AR-JDBC 5X we need to force a connection
|
162
|
+
ActiveRecord::Base.connection.tap { |conn| conn.tables } # ~ pool.checkout
|
163
|
+
rescue ActiveRecordError, java.util.NoSuchElementException => e
|
164
|
+
# DBCP: Java::JavaUtil::NoSuchElementException: Timeout waiting for idle object
|
165
|
+
if ActiveRecord::VERSION::STRING < '5.2'
|
166
|
+
assert_instance_of ConnectionTimeoutError, e
|
167
|
+
else
|
168
|
+
# TODO unfortunately we can not map a TimeoutError and will end up with a StatementInvalid
|
169
|
+
# from the tables call :
|
170
|
+
# assert_instance_of ConnectionTimeoutError, e
|
171
|
+
assert ActiveRecord::Base.connection_pool.send(:timeout_error?, e)
|
172
|
+
end
|
140
173
|
end
|
141
174
|
|
142
175
|
ensure
|
@@ -151,6 +184,7 @@ module ActiveRecord
|
|
151
184
|
t1 = Thread.new do
|
152
185
|
begin
|
153
186
|
conn = ActiveRecord::Base.connection
|
187
|
+
conn.tables # force connection
|
154
188
|
t1_ready.push(conn)
|
155
189
|
t1_block.pop # await
|
156
190
|
rescue => e
|
@@ -165,6 +199,7 @@ module ActiveRecord
|
|
165
199
|
threads << Thread.new do
|
166
200
|
begin
|
167
201
|
conn = ActiveRecord::Base.connection
|
202
|
+
conn.tables # force connection
|
168
203
|
threads_block.update { |v| v + 1 }
|
169
204
|
threads_ready << i
|
170
205
|
while threads_block.value != -1 # await
|
@@ -186,7 +221,7 @@ module ActiveRecord
|
|
186
221
|
|
187
222
|
t2 = Thread.new do
|
188
223
|
begin
|
189
|
-
ActiveRecord::Base.connection
|
224
|
+
ActiveRecord::Base.connection.tap { |conn| conn.tables }
|
190
225
|
rescue => e
|
191
226
|
puts "t2 thread failed: #{e.inspect}"
|
192
227
|
end
|
@@ -214,64 +249,61 @@ module ActiveRecord
|
|
214
249
|
threads && threads.each(&:join)
|
215
250
|
end
|
216
251
|
|
217
|
-
|
252
|
+
# @override
|
253
|
+
def test_pooled_connection_checkin_two
|
254
|
+
checkout_checkin_connections_loop 2, 3
|
218
255
|
|
219
|
-
|
220
|
-
|
256
|
+
assert_equal 3, @connection_count
|
257
|
+
assert_equal 0, @timed_out
|
258
|
+
assert_equal 1, @pool.connections.size
|
221
259
|
end
|
222
260
|
|
223
|
-
|
261
|
+
protected
|
224
262
|
|
225
|
-
|
226
|
-
|
263
|
+
def unwrap_connection(connection)
|
264
|
+
# NOTE: AR-JDBC 5X messed up jdbc_connection(true) - throws a NPE, work-around:
|
265
|
+
connection.tables # force underlying connection into an initialized state ^^^
|
227
266
|
|
228
|
-
|
229
|
-
|
267
|
+
jdbc_connection = connection.jdbc_connection(true)
|
268
|
+
begin
|
269
|
+
jdbc_connection.delegate
|
270
|
+
rescue NoMethodError
|
271
|
+
jdbc_connection
|
272
|
+
end
|
230
273
|
end
|
231
274
|
|
232
|
-
def
|
233
|
-
|
234
|
-
def self.close_data_source
|
235
|
-
@@data_source.send(:close, true) if @@data_source
|
275
|
+
def change_pool_size(size)
|
276
|
+
# noop - @pool.instance_variable_set(:@size, size)
|
236
277
|
end
|
237
278
|
|
238
|
-
def
|
239
|
-
|
240
|
-
def teardown
|
241
|
-
self.class.close_data_source
|
279
|
+
def change_pool_checkout_timeout(timeout)
|
280
|
+
# noop - @pool.instance_variable_set(:@checkout_timeout, timeout)
|
242
281
|
end
|
243
282
|
|
244
283
|
end
|
245
284
|
|
246
|
-
class
|
285
|
+
class ConnectionPoolWrappingTomcatJdbcDataSourceTest < TestBase
|
247
286
|
include ConnectionPoolWrappingDataSourceTestMethods
|
248
287
|
|
249
288
|
def self.build_data_source(config)
|
250
|
-
|
289
|
+
build_tomcat_jdbc_data_source(config)
|
251
290
|
end
|
252
291
|
|
253
|
-
def self.jndi_name; 'jdbc/
|
292
|
+
def self.jndi_name; 'jdbc/TestTomcatJdbcDB' end
|
254
293
|
|
255
294
|
def self.close_data_source
|
256
|
-
@@data_source.close if @@data_source
|
295
|
+
@@data_source.send(:close, true) if @@data_source
|
257
296
|
end
|
258
297
|
|
259
298
|
def max_pool_size; @@data_source.max_active end
|
260
299
|
|
261
300
|
def teardown
|
262
|
-
self.class.
|
263
|
-
end
|
264
|
-
|
265
|
-
protected
|
266
|
-
|
267
|
-
def unwrap_connection(connection)
|
268
|
-
connection = connection.jdbc_connection(true)
|
269
|
-
connection.delegate
|
301
|
+
self.class.close_data_source
|
270
302
|
end
|
271
303
|
|
272
304
|
end
|
273
305
|
|
274
|
-
class
|
306
|
+
class ConnectionPoolWrappingTomcatDbcpDataSourceTest < TestBase
|
275
307
|
include ConnectionPoolWrappingDataSourceTestMethods
|
276
308
|
|
277
309
|
def self.build_data_source(config)
|
@@ -292,50 +324,6 @@ module ActiveRecord
|
|
292
324
|
|
293
325
|
protected
|
294
326
|
|
295
|
-
def unwrap_connection(connection)
|
296
|
-
connection = connection.jdbc_connection(true)
|
297
|
-
connection.delegate
|
298
|
-
end
|
299
|
-
|
300
|
-
end
|
301
|
-
|
302
|
-
class ConnectionPoolWrappingC3P0DataSourceTest < TestBase
|
303
|
-
include ConnectionPoolWrappingDataSourceTestMethods
|
304
|
-
|
305
|
-
def self.build_data_source(config)
|
306
|
-
build_c3p0_data_source(config)
|
307
|
-
end
|
308
|
-
|
309
|
-
def self.jndi_config
|
310
|
-
config = super
|
311
|
-
config[:connection_alive_sql] = 'SELECT 1' if old_c3p0?
|
312
|
-
config
|
313
|
-
end
|
314
|
-
|
315
|
-
def self.old_c3p0?
|
316
|
-
if c3p0_jar = $CLASSPATH.find { |jar| jar =~ /c3p0/ }
|
317
|
-
if match = File.basename(c3p0_jar).match(/c3p0\-(.*).jar/)
|
318
|
-
return true if match[1] <= '0.9.2.1'
|
319
|
-
end
|
320
|
-
return false
|
321
|
-
end
|
322
|
-
nil
|
323
|
-
end
|
324
|
-
|
325
|
-
def test_full_pool_blocks
|
326
|
-
return if self.class.old_c3p0?
|
327
|
-
super
|
328
|
-
end
|
329
|
-
|
330
|
-
def self.jndi_name; 'jdbc/TestC3P0DB' end
|
331
|
-
|
332
|
-
def max_pool_size; @@data_source.max_pool_size end
|
333
|
-
|
334
|
-
def teardown
|
335
|
-
# self.class.close_data_source # @@data_source = nil
|
336
|
-
self.class.establish_jndi_connection # for next test
|
337
|
-
end
|
338
|
-
|
339
327
|
end
|
340
328
|
|
341
329
|
class ConnectionPoolWrappingHikariDataSourceTest < TestBase
|
@@ -368,4 +356,4 @@ module ActiveRecord
|
|
368
356
|
|
369
357
|
end
|
370
358
|
end
|
371
|
-
end
|
359
|
+
end
|
@@ -4,7 +4,8 @@ module ActiveRecord
|
|
4
4
|
module Bogacs
|
5
5
|
class ShareablePool
|
6
6
|
|
7
|
-
|
7
|
+
# TODO: ShareablePool is pretty much broken since 0.7 :
|
8
|
+
class ConnectionPoolTest #< TestBase
|
8
9
|
|
9
10
|
include ConnectionAdapters::ConnectionPoolTestMethods
|
10
11
|
|
@@ -24,7 +25,8 @@ module ActiveRecord
|
|
24
25
|
|
25
26
|
end
|
26
27
|
|
27
|
-
|
28
|
+
# TODO: ShareablePool is pretty much broken since 0.7 :
|
29
|
+
class PoolAPITest #< TestBase
|
28
30
|
|
29
31
|
def setup; ActiveRecord::Base.connection end
|
30
32
|
# def teardown; ActiveRecord::Base.connection_pool.reap end
|
@@ -123,7 +125,8 @@ module ActiveRecord
|
|
123
125
|
|
124
126
|
end
|
125
127
|
|
126
|
-
|
128
|
+
# TODO: ShareablePool is pretty much broken since 0.7 :
|
129
|
+
class CustomAPITest #< TestBase
|
127
130
|
|
128
131
|
def setup
|
129
132
|
connection_pool.disconnect!
|
@@ -4,7 +4,8 @@ module ActiveRecord
|
|
4
4
|
module Bogacs
|
5
5
|
class ShareablePool
|
6
6
|
|
7
|
-
|
7
|
+
# TODO: ShareablePool is pretty much broken since 0.7 :
|
8
|
+
class ConnectionSharingTest #< TestBase
|
8
9
|
include TestHelper
|
9
10
|
|
10
11
|
def setup
|
@@ -170,7 +171,7 @@ module ActiveRecord
|
|
170
171
|
assert shared_connection?(conn)
|
171
172
|
conn
|
172
173
|
end
|
173
|
-
|
174
|
+
|
174
175
|
assert_equal 5, shared_conns.uniq.size
|
175
176
|
|
176
177
|
# still one left for normal connections :
|