activerecord-bogacs 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/active_record/bogacs/default_pool.rb +11 -6
- data/lib/active_record/bogacs/false_pool.rb +17 -8
- data/lib/active_record/bogacs/pool_support.rb +3 -3
- data/lib/active_record/bogacs/shareable_pool.rb +37 -38
- data/lib/active_record/bogacs/version.rb +1 -1
- data/test/active_record/bogacs/shareable_pool/connection_pool_test.rb +2 -4
- data/test/active_record/bogacs/shareable_pool/connection_sharing_test.rb +2 -3
- data/test/active_record/bogacs/shareable_pool_helper.rb +2 -2
- data/test/test_helper.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8272c1dff28e707a092e34ec3e95a0bcf76f31c7b38074da474db9e5cf520edd
|
4
|
+
data.tar.gz: fe9a92843c1b94098e9de4e85d830f96357aa8b49a0e769001eb14d37a71d334
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a9ccd085265c8f744dd7d7ef95dd38918ef2b37c029d1ad19a09322d727fa7a080f895ab14bab005cd54887402090798750a3ad9c1f6f7d0b8456a205ae7cd08
|
7
|
+
data.tar.gz: 40031eed7a1628094fc21d105006e32e06ab48b0890fa0abeb8379c2d513527a01c520e124438bb7dd380448e66cb8b3a2947beaf1cd15f1f2d074645b0b97d8
|
@@ -248,7 +248,7 @@ module ActiveRecord
|
|
248
248
|
#
|
249
249
|
# @return [ActiveRecord::ConnectionAdapters::AbstractAdapter]
|
250
250
|
def connection
|
251
|
-
connection_id =
|
251
|
+
connection_id = connection_cache_key(current_thread)
|
252
252
|
conn = @thread_cached_conns.fetch(connection_id, nil)
|
253
253
|
conn = ( @thread_cached_conns[connection_id] ||= checkout ) unless conn
|
254
254
|
conn
|
@@ -258,7 +258,7 @@ module ActiveRecord
|
|
258
258
|
#
|
259
259
|
# @return [true, false]
|
260
260
|
def active_connection?
|
261
|
-
connection_id =
|
261
|
+
connection_id = connection_cache_key(current_thread)
|
262
262
|
@thread_cached_conns.fetch(connection_id, nil)
|
263
263
|
end
|
264
264
|
|
@@ -266,7 +266,7 @@ module ActiveRecord
|
|
266
266
|
# #release_connection releases the connection-thread association
|
267
267
|
# and returns the connection to the pool.
|
268
268
|
def release_connection(owner_thread = Thread.current)
|
269
|
-
conn = @thread_cached_conns.delete(
|
269
|
+
conn = @thread_cached_conns.delete(connection_cache_key(owner_thread))
|
270
270
|
checkin conn if conn
|
271
271
|
end
|
272
272
|
|
@@ -276,7 +276,7 @@ module ActiveRecord
|
|
276
276
|
#
|
277
277
|
# @yield [ActiveRecord::ConnectionAdapters::AbstractAdapter]
|
278
278
|
def with_connection
|
279
|
-
connection_id =
|
279
|
+
connection_id = connection_cache_key
|
280
280
|
unless conn = @thread_cached_conns[connection_id]
|
281
281
|
conn = connection
|
282
282
|
fresh_connection = true
|
@@ -333,7 +333,7 @@ module ActiveRecord
|
|
333
333
|
# See AbstractAdapter#discard!
|
334
334
|
def discard! # :nodoc:
|
335
335
|
synchronize do
|
336
|
-
return if
|
336
|
+
return if discarded?
|
337
337
|
@connected.make_false
|
338
338
|
|
339
339
|
@connections.each do |conn|
|
@@ -342,6 +342,11 @@ module ActiveRecord
|
|
342
342
|
@connections = @available = @thread_cached_conns = nil
|
343
343
|
end
|
344
344
|
end
|
345
|
+
|
346
|
+
def discarded? # :nodoc:
|
347
|
+
@connections.nil?
|
348
|
+
end
|
349
|
+
|
345
350
|
def clear_reloadable_connections!
|
346
351
|
synchronize do
|
347
352
|
@thread_cached_conns.clear
|
@@ -566,7 +571,7 @@ module ActiveRecord
|
|
566
571
|
#--
|
567
572
|
# if owner_thread param is omitted, this must be called in synchronize block
|
568
573
|
def remove_connection_from_thread_cache(conn, owner_thread = conn.owner)
|
569
|
-
@thread_cached_conns.delete_pair(
|
574
|
+
@thread_cached_conns.delete_pair(connection_cache_key(owner_thread), conn)
|
570
575
|
end
|
571
576
|
alias_method :release, :remove_connection_from_thread_cache
|
572
577
|
|
@@ -37,19 +37,24 @@ module ActiveRecord
|
|
37
37
|
# @private
|
38
38
|
def checkout_timeout; end
|
39
39
|
|
40
|
+
# @override
|
41
|
+
# def connection_cache_key(owner_thread = Thread.current)
|
42
|
+
# owner_thread
|
43
|
+
# end
|
44
|
+
|
40
45
|
# Retrieve the connection associated with the current thread, or call
|
41
46
|
# #checkout to obtain one if necessary.
|
42
47
|
#
|
43
48
|
# #connection can be called any number of times; the connection is
|
44
49
|
# held in a hash keyed by the thread id.
|
45
50
|
def connection
|
46
|
-
connection_id =
|
51
|
+
connection_id = connection_cache_key(current_thread)
|
47
52
|
@thread_cached_conns[connection_id] ||= checkout
|
48
53
|
end
|
49
54
|
|
50
55
|
# Is there an open connection that is being used for the current thread?
|
51
56
|
def active_connection?
|
52
|
-
connection_id =
|
57
|
+
connection_id = connection_cache_key(current_thread)
|
53
58
|
@thread_cached_conns[connection_id]
|
54
59
|
end
|
55
60
|
|
@@ -57,7 +62,7 @@ module ActiveRecord
|
|
57
62
|
# #release_connection releases the connection-thread association
|
58
63
|
# and returns the connection to the pool.
|
59
64
|
def release_connection(owner_thread = Thread.current)
|
60
|
-
conn = @thread_cached_conns.delete(
|
65
|
+
conn = @thread_cached_conns.delete(connection_cache_key(owner_thread))
|
61
66
|
checkin conn if conn
|
62
67
|
end
|
63
68
|
|
@@ -65,7 +70,7 @@ module ActiveRecord
|
|
65
70
|
# exists checkout a connection, yield it to the block, and checkin the
|
66
71
|
# connection when finished.
|
67
72
|
def with_connection
|
68
|
-
connection_id =
|
73
|
+
connection_id = connection_cache_key
|
69
74
|
unless conn = @thread_cached_conns[connection_id]
|
70
75
|
conn = connection
|
71
76
|
fresh_connection = true
|
@@ -100,7 +105,7 @@ module ActiveRecord
|
|
100
105
|
|
101
106
|
def discard! # :nodoc:
|
102
107
|
synchronize do
|
103
|
-
return if
|
108
|
+
return if discarded?
|
104
109
|
@connected.make_false
|
105
110
|
|
106
111
|
connections.each do |conn|
|
@@ -110,6 +115,10 @@ module ActiveRecord
|
|
110
115
|
end
|
111
116
|
end
|
112
117
|
|
118
|
+
def discarded? # :nodoc:
|
119
|
+
@thread_cached_conns.nil?
|
120
|
+
end
|
121
|
+
|
113
122
|
# Clears the cache which maps classes.
|
114
123
|
def clear_reloadable_connections!
|
115
124
|
synchronize do
|
@@ -142,7 +151,7 @@ module ActiveRecord
|
|
142
151
|
# are no longer alive.
|
143
152
|
# @private AR 3.2 compatibility
|
144
153
|
def clear_stale_cached_connections!
|
145
|
-
keys = Thread.list.find_all { |t| t.alive? }.map { |t|
|
154
|
+
keys = Thread.list.find_all { |t| t.alive? }.map { |t| connection_cache_key(t) }
|
146
155
|
keys = @thread_cached_conns.keys - keys
|
147
156
|
keys.each do |key|
|
148
157
|
if conn = @thread_cached_conns[key]
|
@@ -220,10 +229,10 @@ module ActiveRecord
|
|
220
229
|
end
|
221
230
|
|
222
231
|
def release(conn, owner = conn.owner)
|
223
|
-
thread_id =
|
232
|
+
thread_id = connection_cache_key(owner) unless owner.nil?
|
224
233
|
|
225
234
|
thread_id ||=
|
226
|
-
if @thread_cached_conns[conn_id =
|
235
|
+
if @thread_cached_conns[conn_id = connection_cache_key].equal?(conn)
|
227
236
|
conn_id
|
228
237
|
else
|
229
238
|
connections = @thread_cached_conns
|
@@ -24,11 +24,11 @@ module ActiveRecord
|
|
24
24
|
conn
|
25
25
|
end
|
26
26
|
|
27
|
-
# @
|
28
|
-
|
27
|
+
# @override (previously named current_connection_id)
|
28
|
+
# @private connection_cache_key for AR (5.2) compatibility
|
29
|
+
def connection_cache_key(owner_thread = Thread.current)
|
29
30
|
owner_thread.object_id
|
30
31
|
end
|
31
|
-
alias_method :connection_cache_key, :current_connection_id # for AR (5.2) compatibility
|
32
32
|
|
33
33
|
# @note Method not part of the pre 4.0 API (does no exist).
|
34
34
|
def remove(conn)
|
@@ -14,10 +14,9 @@ require 'active_record/bogacs/pool_support'
|
|
14
14
|
#
|
15
15
|
module ActiveRecord
|
16
16
|
module Bogacs
|
17
|
-
class ShareablePool <
|
18
|
-
include PoolSupport
|
17
|
+
class ShareablePool < DefaultPool
|
19
18
|
|
20
|
-
include ThreadSafe::
|
19
|
+
include ::Concurrent::ThreadSafe::Util::CheapLockable
|
21
20
|
|
22
21
|
AtomicReference = ::Concurrent::AtomicReference
|
23
22
|
|
@@ -28,38 +27,35 @@ module ActiveRecord
|
|
28
27
|
|
29
28
|
# @override
|
30
29
|
def initialize(spec)
|
31
|
-
super(spec)
|
30
|
+
super(spec)
|
32
31
|
shared_size = spec.config[:shared_pool]
|
33
32
|
shared_size = shared_size ? shared_size.to_f : DEFAULT_SHARED_POOL
|
34
33
|
# size 0.0 - 1.0 assumes percentage of the pool size
|
35
34
|
shared_size = ( @size * shared_size ).round if shared_size <= 1.0
|
36
35
|
@shared_size = shared_size.to_i
|
37
|
-
@shared_connections = ThreadSafe::Map.new # :
|
36
|
+
@shared_connections = ThreadSafe::Map.new # initial_capacity: @shared_size
|
38
37
|
end
|
39
38
|
|
40
39
|
# @override
|
41
40
|
def connection
|
42
|
-
|
43
|
-
super # @reserved_connections.compute_if_absent(current_connection_id) { checkout }
|
44
|
-
end
|
41
|
+
current_thread[shared_connection_key] || super
|
45
42
|
end
|
46
43
|
|
47
44
|
# @override
|
48
45
|
def active_connection?
|
49
|
-
|
50
|
-
|
51
|
-
end
|
52
|
-
super_active_connection? current_connection_id
|
46
|
+
return true if current_thread[shared_connection_key]
|
47
|
+
has_active_connection? # super
|
53
48
|
end
|
54
49
|
|
55
50
|
# @override called from ConnectionManagement middle-ware (when finished)
|
56
|
-
def release_connection(
|
57
|
-
|
51
|
+
def release_connection(owner_thread = Thread.current)
|
52
|
+
conn_id = connection_cache_key(owner_thread)
|
53
|
+
if reserved_conn = @thread_cached_conns.delete(conn_id)
|
58
54
|
if shared_count = @shared_connections[reserved_conn]
|
59
|
-
|
55
|
+
cheap_synchronize do # lock due #get_shared_connection ... not needed ?!
|
60
56
|
# NOTE: the other option is to not care about shared here at all ...
|
61
57
|
if shared_count.get == 0 # releasing a shared connection
|
62
|
-
release_shared_connection(reserved_conn)
|
58
|
+
release_shared_connection(reserved_conn, owner_thread)
|
63
59
|
#else return false
|
64
60
|
end
|
65
61
|
end
|
@@ -101,14 +97,14 @@ module ActiveRecord
|
|
101
97
|
|
102
98
|
# Custom API :
|
103
99
|
|
104
|
-
def release_shared_connection(connection)
|
100
|
+
def release_shared_connection(connection, owner_thread = Thread.current)
|
105
101
|
shared_conn_key = shared_connection_key
|
106
|
-
if connection ==
|
107
|
-
|
102
|
+
if connection == owner_thread[shared_conn_key]
|
103
|
+
owner_thread[shared_conn_key] = nil
|
108
104
|
end
|
109
105
|
|
110
106
|
@shared_connections.delete(connection)
|
111
|
-
|
107
|
+
shared_checkin connection # synchronized
|
112
108
|
end
|
113
109
|
|
114
110
|
def with_shared_connection
|
@@ -121,9 +117,8 @@ module ActiveRecord
|
|
121
117
|
|
122
118
|
start = Time.now if DEBUG
|
123
119
|
begin
|
124
|
-
connection_id = current_connection_id
|
125
120
|
# if there's a 'regular' connection on the thread use it as super
|
126
|
-
if
|
121
|
+
if has_active_connection? # for current thread
|
127
122
|
connection = self.connection # do not mark as shared
|
128
123
|
DEBUG && debug("with_shared_conn 10 got active = #{connection.to_s}")
|
129
124
|
# otherwise if we have a shared connection - use that one :
|
@@ -131,6 +126,7 @@ module ActiveRecord
|
|
131
126
|
emulated_checkout(connection); shared = true
|
132
127
|
DEBUG && debug("with_shared_conn 20 got shared = #{connection.to_s}")
|
133
128
|
else
|
129
|
+
shared = true
|
134
130
|
synchronize do
|
135
131
|
# check shared again as/if threads end up sync-ing up here :
|
136
132
|
if connection = get_shared_connection
|
@@ -144,7 +140,6 @@ module ActiveRecord
|
|
144
140
|
DEBUG && debug("with_shared_conn 30 acq shared = #{connection.to_s}")
|
145
141
|
end
|
146
142
|
end
|
147
|
-
shared = true
|
148
143
|
end
|
149
144
|
|
150
145
|
Thread.current[shared_conn_key] = connection if shared
|
@@ -152,23 +147,17 @@ module ActiveRecord
|
|
152
147
|
DEBUG && debug("with_shared_conn obtaining a connection took #{(Time.now - start) * 1000}ms")
|
153
148
|
yield connection
|
154
149
|
ensure
|
155
|
-
Thread.current[shared_conn_key] = nil
|
156
|
-
rem_shared_connection(connection) if shared
|
150
|
+
Thread.current[shared_conn_key] = nil if shared
|
151
|
+
rem_shared_connection(connection) if shared && connection
|
157
152
|
end
|
158
153
|
end
|
159
154
|
|
160
155
|
private
|
161
156
|
|
162
|
-
def
|
163
|
-
|
157
|
+
def has_active_connection? # super.active_connection?
|
158
|
+
@thread_cached_conns.fetch(connection_cache_key(current_thread), nil)
|
164
159
|
end
|
165
160
|
|
166
|
-
def super_active_connection?(connection_id = current_connection_id)
|
167
|
-
synchronize do
|
168
|
-
(@reserved_connections[connection_id] || ( return false )).in_use?
|
169
|
-
end
|
170
|
-
end if ActiveRecord::VERSION::MAJOR < 4
|
171
|
-
|
172
161
|
def acquire_connection_no_wait?
|
173
162
|
synchronize do
|
174
163
|
@connections.size < @size || @available.send(:can_remove_no_wait?)
|
@@ -214,7 +203,7 @@ module ActiveRecord
|
|
214
203
|
end
|
215
204
|
|
216
205
|
# we did as much as could without a lock - now sync due possible release
|
217
|
-
|
206
|
+
cheap_synchronize do # TODO although this likely might be avoided ...
|
218
207
|
# should try again if possibly the same connection got released :
|
219
208
|
unless least_count = @shared_connections[least_shared]
|
220
209
|
DEBUG && debug(" get_shared_conn retry (connection got released)")
|
@@ -234,7 +223,7 @@ module ActiveRecord
|
|
234
223
|
def rem_shared_connection(connection)
|
235
224
|
if shared_count = @shared_connections[connection]
|
236
225
|
# shared_count.update { |v| v - 1 } # NOTE: likely fine without lock!
|
237
|
-
|
226
|
+
cheap_synchronize do # give it back to the pool
|
238
227
|
shared_count.update { |v| v - 1 } # might give it back if :
|
239
228
|
release_shared_connection(connection) if shared_count.get == 0
|
240
229
|
end
|
@@ -243,12 +232,22 @@ module ActiveRecord
|
|
243
232
|
|
244
233
|
def emulated_checkin(connection)
|
245
234
|
# NOTE: not sure we'd like to run `run_callbacks :checkin {}` here ...
|
246
|
-
connection.expire
|
235
|
+
connection.expire if connection.owner.equal? Thread.current
|
247
236
|
end
|
248
237
|
|
249
238
|
def emulated_checkout(connection)
|
250
239
|
# NOTE: not sure we'd like to run `run_callbacks :checkout {}` here ...
|
251
|
-
connection.lease
|
240
|
+
connection.lease unless connection.in_use? # connection.verify! auto-reconnect should do this
|
241
|
+
end
|
242
|
+
|
243
|
+
def shared_checkin(conn)
|
244
|
+
#conn.lock.synchronize do
|
245
|
+
synchronize do
|
246
|
+
_run_checkin_callbacks(conn) if conn.owner.equal? Thread.current
|
247
|
+
|
248
|
+
@available.add conn
|
249
|
+
end
|
250
|
+
#end
|
252
251
|
end
|
253
252
|
|
254
253
|
def shared_connection_key
|
@@ -265,7 +264,7 @@ module ActiveRecord
|
|
265
264
|
when 'true' then ActiveRecord::Base.logger
|
266
265
|
else File.expand_path(debug)
|
267
266
|
end
|
268
|
-
require 'logger'; Logger.new log_dev
|
267
|
+
log_dev.respond_to?(:debug) ? log_dev : (require 'logger'; Logger.new log_dev)
|
269
268
|
else nil
|
270
269
|
end
|
271
270
|
end
|
@@ -4,8 +4,7 @@ module ActiveRecord
|
|
4
4
|
module Bogacs
|
5
5
|
class ShareablePool
|
6
6
|
|
7
|
-
|
8
|
-
class ConnectionPoolTest #< TestBase
|
7
|
+
class ConnectionPoolTest < TestBase
|
9
8
|
|
10
9
|
include ConnectionAdapters::ConnectionPoolTestMethods
|
11
10
|
|
@@ -25,8 +24,7 @@ module ActiveRecord
|
|
25
24
|
|
26
25
|
end
|
27
26
|
|
28
|
-
|
29
|
-
class PoolAPITest #< TestBase
|
27
|
+
class PoolAPITest < TestBase
|
30
28
|
|
31
29
|
def setup; ActiveRecord::Base.connection end
|
32
30
|
# def teardown; ActiveRecord::Base.connection_pool.reap end
|
@@ -4,8 +4,7 @@ module ActiveRecord
|
|
4
4
|
module Bogacs
|
5
5
|
class ShareablePool
|
6
6
|
|
7
|
-
|
8
|
-
class ConnectionSharingTest #< TestBase
|
7
|
+
class ConnectionSharingTest < TestBase
|
9
8
|
include TestHelper
|
10
9
|
|
11
10
|
def setup
|
@@ -244,7 +243,7 @@ module ActiveRecord
|
|
244
243
|
sleep(0.005)
|
245
244
|
|
246
245
|
with_shared_connection do |conn2|
|
247
|
-
assert conn1
|
246
|
+
assert conn1.equal?(conn2)
|
248
247
|
|
249
248
|
# we can not do any-more here without a timeout :
|
250
249
|
failed = nil
|
@@ -24,7 +24,7 @@ module ActiveRecord
|
|
24
24
|
alias_method :connections, :initialized_connections
|
25
25
|
|
26
26
|
def reserved_connections
|
27
|
-
|
27
|
+
connection_pool.instance_variable_get :@thread_cached_conns
|
28
28
|
end
|
29
29
|
|
30
30
|
def available_connections
|
@@ -70,7 +70,7 @@ module ActiveRecord
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def self.shutdown
|
73
|
-
|
73
|
+
ActiveRecord::Base.connection_pool.disconnect!
|
74
74
|
ConnectionAdapters::ConnectionHandler.connection_pool_class = ConnectionAdapters::ConnectionPool
|
75
75
|
end
|
76
76
|
|
data/test/test_helper.rb
CHANGED
@@ -55,7 +55,7 @@ config[:'prepared_statements'] = prepared_statements if prepared_statements
|
|
55
55
|
#jdbc_properties = { 'logUnclosedConnections' => true, 'loginTimeout' => 5 }
|
56
56
|
#config[:'properties'] = jdbc_properties
|
57
57
|
config[:'properties'] ||= {}
|
58
|
-
config[:'properties']['useSSL'] ||= 'false' if config[:adapter].
|
58
|
+
config[:'properties']['useSSL'] ||= 'false' if config[:adapter].start_with?('mysql')
|
59
59
|
|
60
60
|
checkout_timeout = ENV['AR_POOL_CHECKOUT_TIMEOUT'] || checkout_timeout
|
61
61
|
config[:'checkout_timeout'] = checkout_timeout.to_f if checkout_timeout
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-bogacs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karol Bucek
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-08-
|
11
|
+
date: 2022-08-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|