activerecord-bogacs 0.5.1 → 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/.github/workflows/test.yml +82 -0
- data/Gemfile +2 -15
- data/LICENSE.txt +1 -1
- data/README.md +37 -17
- data/Rakefile +8 -6
- data/activerecord-bogacs.gemspec +6 -6
- data/lib/active_record/bogacs/connection_handler.rb +36 -0
- data/lib/active_record/bogacs/default_pool.rb +256 -91
- data/lib/active_record/bogacs/false_pool.rb +97 -54
- data/lib/active_record/bogacs/pool_support.rb +26 -8
- data/lib/active_record/bogacs/railtie.rb +17 -0
- data/lib/active_record/bogacs/shareable_pool.rb +41 -46
- 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 +15 -20
- data/lib/active_record/bogacs/version.rb +1 -1
- data/lib/active_record/bogacs.rb +6 -2
- data/lib/active_record/connection_adapters/adapter_compat.rb +63 -17
- data/lib/active_record/connection_adapters/pool_class.rb +33 -2
- 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 +2 -1
- data/test/active_record/bogacs/shareable_pool/connection_sharing_test.rb +2 -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 +41 -26
- metadata +33 -17
@@ -1,5 +1,8 @@
|
|
1
1
|
require 'active_record/version'
|
2
2
|
|
3
|
+
require 'concurrent/atomic/atomic_boolean'
|
4
|
+
|
5
|
+
require 'active_record/connection_adapters/adapter_compat'
|
3
6
|
require 'active_record/bogacs/pool_support'
|
4
7
|
require 'active_record/bogacs/thread_safe'
|
5
8
|
|
@@ -16,17 +19,17 @@ module ActiveRecord
|
|
16
19
|
attr_reader :size, :spec
|
17
20
|
|
18
21
|
def initialize(spec)
|
19
|
-
|
22
|
+
super()
|
20
23
|
|
21
24
|
@spec = spec
|
22
25
|
@size = nil
|
23
26
|
@automatic_reconnect = nil
|
27
|
+
@lock_thread = false
|
24
28
|
|
25
|
-
@
|
26
|
-
end
|
29
|
+
@thread_cached_conns = ThreadSafe::Map.new
|
27
30
|
|
28
|
-
|
29
|
-
|
31
|
+
@connected = ::Concurrent::AtomicBoolean.new
|
32
|
+
end
|
30
33
|
|
31
34
|
# @private attr_reader :reaper
|
32
35
|
def reaper; end
|
@@ -34,26 +37,32 @@ module ActiveRecord
|
|
34
37
|
# @private
|
35
38
|
def checkout_timeout; end
|
36
39
|
|
40
|
+
# @override
|
41
|
+
# def connection_cache_key(owner_thread = Thread.current)
|
42
|
+
# owner_thread
|
43
|
+
# end
|
44
|
+
|
37
45
|
# Retrieve the connection associated with the current thread, or call
|
38
46
|
# #checkout to obtain one if necessary.
|
39
47
|
#
|
40
48
|
# #connection can be called any number of times; the connection is
|
41
49
|
# held in a hash keyed by the thread id.
|
42
50
|
def connection
|
43
|
-
|
51
|
+
connection_id = connection_cache_key(current_thread)
|
52
|
+
@thread_cached_conns[connection_id] ||= checkout
|
44
53
|
end
|
45
54
|
|
46
55
|
# Is there an open connection that is being used for the current thread?
|
47
56
|
def active_connection?
|
48
|
-
|
49
|
-
|
57
|
+
connection_id = connection_cache_key(current_thread)
|
58
|
+
@thread_cached_conns[connection_id]
|
50
59
|
end
|
51
60
|
|
52
61
|
# Signal that the thread is finished with the current connection.
|
53
62
|
# #release_connection releases the connection-thread association
|
54
63
|
# and returns the connection to the pool.
|
55
|
-
def release_connection(
|
56
|
-
conn = @
|
64
|
+
def release_connection(owner_thread = Thread.current)
|
65
|
+
conn = @thread_cached_conns.delete(connection_cache_key(owner_thread))
|
57
66
|
checkin conn if conn
|
58
67
|
end
|
59
68
|
|
@@ -61,41 +70,68 @@ module ActiveRecord
|
|
61
70
|
# exists checkout a connection, yield it to the block, and checkin the
|
62
71
|
# connection when finished.
|
63
72
|
def with_connection
|
64
|
-
connection_id =
|
65
|
-
|
66
|
-
|
73
|
+
connection_id = connection_cache_key
|
74
|
+
unless conn = @thread_cached_conns[connection_id]
|
75
|
+
conn = connection
|
76
|
+
fresh_connection = true
|
77
|
+
end
|
78
|
+
yield conn
|
67
79
|
ensure
|
68
|
-
release_connection
|
80
|
+
release_connection if fresh_connection
|
69
81
|
end
|
70
82
|
|
71
83
|
# Returns true if a connection has already been opened.
|
72
|
-
def connected?; @connected end
|
84
|
+
def connected?; @connected.true? end
|
85
|
+
|
86
|
+
# @private replacement for attr_reader :connections
|
87
|
+
def connections; @thread_cached_conns.values end
|
73
88
|
|
74
89
|
# Disconnects all connections in the pool, and clears the pool.
|
75
90
|
def disconnect!
|
76
91
|
synchronize do
|
77
|
-
@connected
|
78
|
-
|
79
|
-
connections = @reserved_connections.values
|
80
|
-
@reserved_connections.clear
|
92
|
+
@connected.make_false
|
81
93
|
|
94
|
+
connections = @thread_cached_conns.values
|
95
|
+
@thread_cached_conns.clear
|
82
96
|
connections.each do |conn|
|
83
|
-
|
97
|
+
if conn.in_use?
|
98
|
+
conn.steal!
|
99
|
+
checkin conn
|
100
|
+
end
|
84
101
|
conn.disconnect!
|
85
102
|
end
|
86
103
|
end
|
87
104
|
end
|
88
105
|
|
106
|
+
def discard! # :nodoc:
|
107
|
+
synchronize do
|
108
|
+
return if discarded?
|
109
|
+
@connected.make_false
|
110
|
+
|
111
|
+
connections.each do |conn|
|
112
|
+
conn.discard!
|
113
|
+
end
|
114
|
+
@thread_cached_conns = nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def discarded? # :nodoc:
|
119
|
+
@thread_cached_conns.nil?
|
120
|
+
end
|
121
|
+
|
89
122
|
# Clears the cache which maps classes.
|
90
123
|
def clear_reloadable_connections!
|
91
124
|
synchronize do
|
92
|
-
@connected
|
125
|
+
@connected.make_false
|
93
126
|
|
94
|
-
connections = @
|
95
|
-
@
|
127
|
+
connections = @thread_cached_conns.values
|
128
|
+
@thread_cached_conns.clear
|
96
129
|
|
97
130
|
connections.each do |conn|
|
98
|
-
|
131
|
+
if conn.in_use?
|
132
|
+
conn.steal!
|
133
|
+
checkin conn
|
134
|
+
end
|
99
135
|
conn.disconnect! if conn.requires_reloading?
|
100
136
|
end
|
101
137
|
end
|
@@ -107,7 +143,7 @@ module ActiveRecord
|
|
107
143
|
def verify_active_connections!
|
108
144
|
synchronize do
|
109
145
|
clear_stale_cached_connections!
|
110
|
-
@
|
146
|
+
@thread_cached_conns.values.each(&:verify!)
|
111
147
|
end
|
112
148
|
end if ActiveRecord::VERSION::MAJOR < 4
|
113
149
|
|
@@ -115,12 +151,12 @@ module ActiveRecord
|
|
115
151
|
# are no longer alive.
|
116
152
|
# @private AR 3.2 compatibility
|
117
153
|
def clear_stale_cached_connections!
|
118
|
-
keys = Thread.list.find_all { |t| t.alive? }.map(
|
119
|
-
keys = @
|
154
|
+
keys = Thread.list.find_all { |t| t.alive? }.map { |t| connection_cache_key(t) }
|
155
|
+
keys = @thread_cached_conns.keys - keys
|
120
156
|
keys.each do |key|
|
121
|
-
if conn = @
|
122
|
-
checkin conn,
|
123
|
-
@
|
157
|
+
if conn = @thread_cached_conns[key]
|
158
|
+
checkin conn, true # no release
|
159
|
+
@thread_cached_conns.delete(key)
|
124
160
|
end
|
125
161
|
end
|
126
162
|
end if ActiveRecord::VERSION::MAJOR < 4
|
@@ -131,12 +167,12 @@ module ActiveRecord
|
|
131
167
|
# @return [ActiveRecord::ConnectionAdapters::AbstractAdapter]
|
132
168
|
# @raise [ActiveRecord::ConnectionTimeoutError] no connection can be obtained from the pool
|
133
169
|
def checkout
|
134
|
-
#
|
135
|
-
|
170
|
+
conn = checkout_new_connection # acquire_connection
|
171
|
+
synchronize do
|
136
172
|
conn.lease
|
137
173
|
_run_checkout_callbacks(conn) # checkout_and_verify(conn)
|
138
|
-
|
139
|
-
|
174
|
+
end
|
175
|
+
conn
|
140
176
|
end
|
141
177
|
|
142
178
|
# Check-in a database connection back into the pool, indicating that you
|
@@ -145,13 +181,9 @@ module ActiveRecord
|
|
145
181
|
# @param conn [ActiveRecord::ConnectionAdapters::AbstractAdapter] connection
|
146
182
|
# object, which was obtained earlier by calling #checkout on this pool
|
147
183
|
# @see #checkout
|
148
|
-
def checkin(conn,
|
149
|
-
release(conn)
|
150
|
-
|
151
|
-
_run_checkin_callbacks(conn)
|
152
|
-
#release conn
|
153
|
-
#@available.add conn
|
154
|
-
#end
|
184
|
+
def checkin(conn, released = nil)
|
185
|
+
release(conn) unless released
|
186
|
+
_run_checkin_callbacks(conn)
|
155
187
|
end
|
156
188
|
|
157
189
|
# Remove a connection from the connection pool. The connection will
|
@@ -165,6 +197,21 @@ module ActiveRecord
|
|
165
197
|
# we do not really manage the connection pool - nothing to do ...
|
166
198
|
end
|
167
199
|
|
200
|
+
def flush(minimum_idle = nil)
|
201
|
+
# we do not really manage the connection pool
|
202
|
+
end
|
203
|
+
|
204
|
+
def flush!
|
205
|
+
reap
|
206
|
+
flush(-1)
|
207
|
+
end
|
208
|
+
|
209
|
+
def stat
|
210
|
+
{
|
211
|
+
connections: connections.size
|
212
|
+
}
|
213
|
+
end
|
214
|
+
|
168
215
|
private
|
169
216
|
|
170
217
|
# @raise [ActiveRecord::ConnectionTimeoutError]
|
@@ -181,34 +228,30 @@ module ActiveRecord
|
|
181
228
|
checkout_new_connection
|
182
229
|
end
|
183
230
|
|
184
|
-
def release(conn, owner =
|
185
|
-
thread_id = owner
|
231
|
+
def release(conn, owner = conn.owner)
|
232
|
+
thread_id = connection_cache_key(owner) unless owner.nil?
|
186
233
|
|
187
234
|
thread_id ||=
|
188
|
-
if @
|
235
|
+
if @thread_cached_conns[conn_id = connection_cache_key].equal?(conn)
|
189
236
|
conn_id
|
190
237
|
else
|
191
|
-
connections = @
|
192
|
-
connections.keys.find { |k| connections[k]
|
238
|
+
connections = @thread_cached_conns
|
239
|
+
connections.keys.find { |k| connections[k].equal?(conn) }
|
193
240
|
end
|
194
241
|
|
195
|
-
@
|
242
|
+
@thread_cached_conns.delete_pair(thread_id, conn) if thread_id
|
196
243
|
end
|
197
244
|
|
198
245
|
def checkout_new_connection
|
199
|
-
# NOTE: automatic reconnect
|
200
|
-
#raise ConnectionNotEstablished unless @automatic_reconnect
|
201
|
-
|
246
|
+
# NOTE: automatic reconnect makes no sense for us!
|
202
247
|
begin
|
203
248
|
conn = new_connection
|
204
|
-
rescue ConnectionTimeoutError => e
|
205
|
-
raise e
|
206
249
|
rescue => e
|
207
|
-
raise ConnectionTimeoutError, e.message if timeout_error?(e)
|
250
|
+
raise ConnectionTimeoutError, e.message if timeout_error?(e) && !e.is_a?(ConnectionTimeoutError)
|
208
251
|
raise e
|
209
252
|
end
|
253
|
+
@connected.make_true
|
210
254
|
conn.pool = self
|
211
|
-
synchronize { @connected = true } if @connected != true
|
212
255
|
conn
|
213
256
|
end
|
214
257
|
|
@@ -1,19 +1,33 @@
|
|
1
|
+
require 'active_record/connection_adapters/abstract/query_cache'
|
1
2
|
|
2
3
|
module ActiveRecord
|
3
4
|
module Bogacs
|
4
5
|
module PoolSupport
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
def self.included(base)
|
8
|
+
base.send :include, ActiveRecord::ConnectionAdapters::QueryCache::ConnectionPoolConfiguration
|
9
|
+
end if ActiveRecord::ConnectionAdapters::QueryCache.const_defined? :ConnectionPoolConfiguration
|
10
|
+
|
11
|
+
attr_accessor :schema_cache
|
12
|
+
|
13
|
+
def lock_thread=(lock_thread)
|
14
|
+
if lock_thread
|
15
|
+
@lock_thread = Thread.current
|
16
|
+
else
|
17
|
+
@lock_thread = nil
|
18
|
+
end
|
19
|
+
end if ActiveRecord::VERSION::MAJOR > 4
|
9
20
|
|
10
21
|
def new_connection
|
11
|
-
Base.send(spec.adapter_method, spec.config)
|
22
|
+
conn = Base.send(spec.adapter_method, spec.config)
|
23
|
+
conn.schema_cache = schema_cache.dup if schema_cache && conn.respond_to?(:schema_cache=)
|
24
|
+
conn
|
12
25
|
end
|
13
26
|
|
14
|
-
|
15
|
-
|
16
|
-
|
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)
|
30
|
+
owner_thread.object_id
|
17
31
|
end
|
18
32
|
|
19
33
|
# @note Method not part of the pre 4.0 API (does no exist).
|
@@ -37,6 +51,10 @@ module ActiveRecord
|
|
37
51
|
|
38
52
|
private
|
39
53
|
|
54
|
+
def current_thread
|
55
|
+
@lock_thread || Thread.current
|
56
|
+
end
|
57
|
+
|
40
58
|
if ActiveRecord::VERSION::STRING > '4.2'
|
41
59
|
|
42
60
|
def _run_checkin_callbacks(conn)
|
@@ -89,4 +107,4 @@ module ActiveRecord
|
|
89
107
|
|
90
108
|
end
|
91
109
|
end
|
92
|
-
end
|
110
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Bogacs
|
3
|
+
class Railtie < Rails::Railtie
|
4
|
+
|
5
|
+
initializer 'active_record.bogacs', :before => 'active_record.initialize_database' do |_|
|
6
|
+
ActiveSupport.on_load :active_record do
|
7
|
+
require 'active_record/bogacs'
|
8
|
+
|
9
|
+
# support for auto-configuring FalsePool (when config[:pool] set to false) :
|
10
|
+
require 'active_record/bogacs/connection_handler'
|
11
|
+
ActiveRecord::Base.default_connection_handler = ConnectionHandler.new
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'active_record/version'
|
2
2
|
require 'active_record/connection_adapters/abstract/connection_pool'
|
3
3
|
|
4
|
-
require '
|
4
|
+
require 'concurrent/atomic/atomic_reference'
|
5
|
+
require 'concurrent/thread_safe/util/cheap_lockable.rb'
|
5
6
|
|
6
7
|
require 'active_record/bogacs/thread_safe'
|
7
8
|
require 'active_record/bogacs/pool_support'
|
@@ -13,17 +14,11 @@ require 'active_record/bogacs/pool_support'
|
|
13
14
|
#
|
14
15
|
module ActiveRecord
|
15
16
|
module Bogacs
|
16
|
-
class ShareablePool <
|
17
|
-
include PoolSupport
|
17
|
+
class ShareablePool < DefaultPool
|
18
18
|
|
19
|
-
|
20
|
-
include ThreadSafe::CheapLockable
|
21
|
-
else
|
22
|
-
alias_method :cheap_synchronize, :synchronize
|
23
|
-
end
|
19
|
+
include ::Concurrent::ThreadSafe::Util::CheapLockable
|
24
20
|
|
25
|
-
|
26
|
-
AtomicReference = ThreadSafe::AtomicReference
|
21
|
+
AtomicReference = ::Concurrent::AtomicReference
|
27
22
|
|
28
23
|
DEFAULT_SHARED_POOL = 0.25 # only allow 25% of the pool size to be shared
|
29
24
|
MAX_THREAD_SHARING = 5 # not really a strict limit but should hold
|
@@ -32,38 +27,35 @@ module ActiveRecord
|
|
32
27
|
|
33
28
|
# @override
|
34
29
|
def initialize(spec)
|
35
|
-
super(spec)
|
30
|
+
super(spec)
|
36
31
|
shared_size = spec.config[:shared_pool]
|
37
32
|
shared_size = shared_size ? shared_size.to_f : DEFAULT_SHARED_POOL
|
38
33
|
# size 0.0 - 1.0 assumes percentage of the pool size
|
39
34
|
shared_size = ( @size * shared_size ).round if shared_size <= 1.0
|
40
35
|
@shared_size = shared_size.to_i
|
41
|
-
@shared_connections = ThreadSafe::Map.new # :
|
36
|
+
@shared_connections = ThreadSafe::Map.new # initial_capacity: @shared_size
|
42
37
|
end
|
43
38
|
|
44
39
|
# @override
|
45
40
|
def connection
|
46
|
-
|
47
|
-
super # @reserved_connections.compute_if_absent(current_connection_id) { checkout }
|
48
|
-
end
|
41
|
+
current_thread[shared_connection_key] || super
|
49
42
|
end
|
50
43
|
|
51
44
|
# @override
|
52
45
|
def active_connection?
|
53
|
-
|
54
|
-
|
55
|
-
end
|
56
|
-
super_active_connection? current_connection_id
|
46
|
+
return true if current_thread[shared_connection_key]
|
47
|
+
has_active_connection? # super
|
57
48
|
end
|
58
49
|
|
59
50
|
# @override called from ConnectionManagement middle-ware (when finished)
|
60
|
-
def release_connection(
|
61
|
-
|
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)
|
62
54
|
if shared_count = @shared_connections[reserved_conn]
|
63
55
|
cheap_synchronize do # lock due #get_shared_connection ... not needed ?!
|
64
56
|
# NOTE: the other option is to not care about shared here at all ...
|
65
57
|
if shared_count.get == 0 # releasing a shared connection
|
66
|
-
release_shared_connection(reserved_conn)
|
58
|
+
release_shared_connection(reserved_conn, owner_thread)
|
67
59
|
#else return false
|
68
60
|
end
|
69
61
|
end
|
@@ -75,18 +67,18 @@ module ActiveRecord
|
|
75
67
|
|
76
68
|
# @override
|
77
69
|
def disconnect!
|
78
|
-
|
70
|
+
synchronize { @shared_connections.clear; super }
|
79
71
|
end
|
80
72
|
|
81
73
|
# @override
|
82
74
|
def clear_reloadable_connections!
|
83
|
-
|
75
|
+
synchronize { @shared_connections.clear; super }
|
84
76
|
end
|
85
77
|
|
86
78
|
# @override
|
87
79
|
# @note called from #reap thus the pool should work with reaper
|
88
80
|
def remove(conn)
|
89
|
-
|
81
|
+
synchronize { @shared_connections.delete(conn); super }
|
90
82
|
end
|
91
83
|
|
92
84
|
# # Return any checked-out connections back to the pool by threads that
|
@@ -105,14 +97,14 @@ module ActiveRecord
|
|
105
97
|
|
106
98
|
# Custom API :
|
107
99
|
|
108
|
-
def release_shared_connection(connection)
|
100
|
+
def release_shared_connection(connection, owner_thread = Thread.current)
|
109
101
|
shared_conn_key = shared_connection_key
|
110
|
-
if connection ==
|
111
|
-
|
102
|
+
if connection == owner_thread[shared_conn_key]
|
103
|
+
owner_thread[shared_conn_key] = nil
|
112
104
|
end
|
113
105
|
|
114
106
|
@shared_connections.delete(connection)
|
115
|
-
|
107
|
+
shared_checkin connection # synchronized
|
116
108
|
end
|
117
109
|
|
118
110
|
def with_shared_connection
|
@@ -125,9 +117,8 @@ module ActiveRecord
|
|
125
117
|
|
126
118
|
start = Time.now if DEBUG
|
127
119
|
begin
|
128
|
-
connection_id = current_connection_id
|
129
120
|
# if there's a 'regular' connection on the thread use it as super
|
130
|
-
if
|
121
|
+
if has_active_connection? # for current thread
|
131
122
|
connection = self.connection # do not mark as shared
|
132
123
|
DEBUG && debug("with_shared_conn 10 got active = #{connection.to_s}")
|
133
124
|
# otherwise if we have a shared connection - use that one :
|
@@ -135,7 +126,8 @@ module ActiveRecord
|
|
135
126
|
emulated_checkout(connection); shared = true
|
136
127
|
DEBUG && debug("with_shared_conn 20 got shared = #{connection.to_s}")
|
137
128
|
else
|
138
|
-
|
129
|
+
shared = true
|
130
|
+
synchronize do
|
139
131
|
# check shared again as/if threads end up sync-ing up here :
|
140
132
|
if connection = get_shared_connection
|
141
133
|
emulated_checkout(connection)
|
@@ -148,7 +140,6 @@ module ActiveRecord
|
|
148
140
|
DEBUG && debug("with_shared_conn 30 acq shared = #{connection.to_s}")
|
149
141
|
end
|
150
142
|
end
|
151
|
-
shared = true
|
152
143
|
end
|
153
144
|
|
154
145
|
Thread.current[shared_conn_key] = connection if shared
|
@@ -156,23 +147,17 @@ module ActiveRecord
|
|
156
147
|
DEBUG && debug("with_shared_conn obtaining a connection took #{(Time.now - start) * 1000}ms")
|
157
148
|
yield connection
|
158
149
|
ensure
|
159
|
-
Thread.current[shared_conn_key] = nil
|
160
|
-
rem_shared_connection(connection) if shared
|
150
|
+
Thread.current[shared_conn_key] = nil if shared
|
151
|
+
rem_shared_connection(connection) if shared && connection
|
161
152
|
end
|
162
153
|
end
|
163
154
|
|
164
155
|
private
|
165
156
|
|
166
|
-
def
|
167
|
-
|
157
|
+
def has_active_connection? # super.active_connection?
|
158
|
+
@thread_cached_conns.fetch(connection_cache_key(current_thread), nil)
|
168
159
|
end
|
169
160
|
|
170
|
-
def super_active_connection?(connection_id = current_connection_id)
|
171
|
-
synchronize do
|
172
|
-
(@reserved_connections[connection_id] || ( return false )).in_use?
|
173
|
-
end
|
174
|
-
end if ActiveRecord::VERSION::MAJOR < 4
|
175
|
-
|
176
161
|
def acquire_connection_no_wait?
|
177
162
|
synchronize do
|
178
163
|
@connections.size < @size || @available.send(:can_remove_no_wait?)
|
@@ -247,12 +232,22 @@ module ActiveRecord
|
|
247
232
|
|
248
233
|
def emulated_checkin(connection)
|
249
234
|
# NOTE: not sure we'd like to run `run_callbacks :checkin {}` here ...
|
250
|
-
connection.expire
|
235
|
+
connection.expire if connection.owner.equal? Thread.current
|
251
236
|
end
|
252
237
|
|
253
238
|
def emulated_checkout(connection)
|
254
239
|
# NOTE: not sure we'd like to run `run_callbacks :checkout {}` here ...
|
255
|
-
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
|
256
251
|
end
|
257
252
|
|
258
253
|
def shared_connection_key
|
@@ -269,7 +264,7 @@ module ActiveRecord
|
|
269
264
|
when 'true' then ActiveRecord::Base.logger
|
270
265
|
else File.expand_path(debug)
|
271
266
|
end
|
272
|
-
require 'logger'; Logger.new log_dev
|
267
|
+
log_dev.respond_to?(:debug) ? log_dev : (require 'logger'; Logger.new log_dev)
|
273
268
|
else nil
|
274
269
|
end
|
275
270
|
end
|
@@ -1,33 +1,29 @@
|
|
1
|
+
require 'concurrent/thread_safe/util/cheap_lockable.rb'
|
2
|
+
|
1
3
|
# @note Inpspired by thread_safe gem's Util::CheapLockable mixin.
|
2
4
|
module ActiveRecord::Bogacs
|
3
5
|
module ThreadSafe
|
4
|
-
|
5
|
-
if engine == 'rbx'
|
6
|
+
if defined? JRUBY_VERSION
|
6
7
|
module Synchronized
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
::
|
8
|
+
if defined? ::JRuby::Util.synchronized # since JRuby 9.3
|
9
|
+
def synchronize
|
10
|
+
::JRuby::Util.synchronized(self) { yield }
|
11
|
+
end
|
12
|
+
else
|
13
|
+
require 'jruby'
|
14
|
+
def synchronize
|
15
|
+
::JRuby.reference0(self).synchronized { yield }
|
15
16
|
end
|
16
17
|
end
|
17
18
|
end
|
18
|
-
|
19
|
+
else
|
20
|
+
require 'concurrent/thread_safe/util/cheap_lockable.rb'
|
21
|
+
|
19
22
|
module Synchronized
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
def synchronize
|
24
|
-
::JRuby.reference0(self).synchronized { yield }
|
25
|
-
end
|
23
|
+
include ::Concurrent::ThreadSafe::Util::CheapLockable
|
24
|
+
alias_method :synchronize, :cheap_synchronize
|
25
|
+
public :synchronize
|
26
26
|
end
|
27
|
-
else
|
28
|
-
require 'thread'; require 'monitor'
|
29
|
-
# on MRI fallback to built-in MonitorMixin
|
30
|
-
Synchronized = MonitorMixin
|
31
27
|
end
|
32
28
|
end
|
33
|
-
end
|
29
|
+
end
|