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.
@@ -49,7 +49,7 @@ module ActiveRecord
49
49
  require 'concurrent/atomic/semaphore.rb'
50
50
  Semaphore = ::Concurrent::Semaphore
51
51
 
52
- def test_selects_non_used_connections
52
+ def test_removes_non_used_connections_from_pool_when_collecting_connections_to_validate
53
53
  assert_equal [], validator.send(:connections)
54
54
 
55
55
  count = AtomicFixnum.new
@@ -67,15 +67,15 @@ module ActiveRecord
67
67
  pool.with_connection { |conn| assert released_conn = conn }
68
68
  }.join
69
69
 
70
-
71
70
  assert_equal 3, pool.connections.size
72
- assert_equal 1, validator.send(:connections).size
73
- assert_equal [ released_conn ], validator.send(:connections)
74
-
75
- semaphore.release 2
71
+ validator.send(:connections)
72
+ assert_equal 2, pool.connections.size
73
+ assert_false pool.connections.include?(released_conn)
74
+ ensure
75
+ semaphore.release 2 if semaphore
76
76
  end
77
77
 
78
- def test_auto_removes_stale_connection_from_pool_when_collecting_connections_to_validate
78
+ def test_removes_stale_connection_from_pool_when_collecting_connections_to_validate
79
79
  conn = connection
80
80
 
81
81
  assert_equal [], validator.send(:connections)
@@ -91,23 +91,15 @@ module ActiveRecord
91
91
  }
92
92
  while count.value < 2; sleep 0.01 end
93
93
 
94
- returned_conn = nil
95
- Thread.new {
96
- pool.with_connection { |conn| assert returned_conn = conn }
97
- }.join
98
-
99
- assert_equal 4, pool.connections.size
94
+ assert_equal 3, pool.connections.size
100
95
  validate_candidates = validator.send(:connections)
101
- assert_equal [ returned_conn ], validate_candidates
102
- assert_equal 4, pool.connections.size
96
+ assert_equal 3, pool.connections.size
103
97
 
104
98
  semaphore.release(2); sleep 0.05
105
99
 
106
- validate_candidates = validator.send(:connections)
107
- assert_equal 2, validate_candidates.size
108
- assert validate_candidates.include?(returned_conn)
109
- assert ! validate_candidates.include?(stale_conn)
110
- assert_equal 3, pool.connections.size
100
+ validator.send(:connections)
101
+ assert ! pool.connections.include?(stale_conn)
102
+ assert_equal 1, pool.connections.size
111
103
  assert ! pool.connections.map(&:object_id).include?(stale_conn.object_id)
112
104
  end
113
105
 
@@ -184,13 +176,13 @@ module ActiveRecord
184
176
  end
185
177
 
186
178
 
187
- def test_validate_returns_invalid_connection_count
188
- conn = connection; threads = []; invalid_conns = []
189
- threads << Thread.new { pool.with_connection { |conn| thread_work(conn, 0.05) } }
190
- threads << Thread.new { pool.with_connection { |conn| thread_work(conn, 0.05); conn.expire; invalid_conns << conn } }
191
- threads << Thread.new { pool.with_connection { |conn| thread_work(conn, 0.05) } }
192
- threads << Thread.new { pool.with_connection { |conn| thread_work(conn, 0.05); conn.expire; invalid_conns << conn } }
193
- threads.each(&:join)
179
+ def test_validate_returns_invalid_connection_count; require 'concurrent/array'
180
+ done = false; conn = connection; threads = []; invalid_conns = Concurrent::Array.new
181
+ threads << Thread.new { pool.with_connection { |conn| thread_work(conn, 0.2); sleep(0.1) until done } }
182
+ threads << Thread.new { pool.with_connection { |conn| thread_work(conn, 0.2); conn.expire; invalid_conns << conn; sleep(0.05) until done } }
183
+ threads << Thread.new { pool.with_connection { |conn| thread_work(conn, 0.2); sleep(0.1) until done } }
184
+ threads << Thread.new { pool.with_connection { |conn| thread_work(conn, 0.2); conn.expire; invalid_conns << conn; sleep(0.05) until done } }
185
+ sleep(0.1) until invalid_conns.size == 2 # threads.each(&:join)
194
186
  assert_equal 5, pool.connections.size
195
187
 
196
188
  invalid_conns.each { |conn| def conn.active?; false end }
@@ -203,6 +195,8 @@ module ActiveRecord
203
195
  result = validator.validate
204
196
  assert_equal 0, result
205
197
  assert_equal 3, pool.connections.size
198
+ ensure
199
+ done = true
206
200
  end
207
201
 
208
202
  private
@@ -245,4 +239,4 @@ module ActiveRecord
245
239
 
246
240
  end
247
241
  end
248
- end
242
+ end
@@ -10,18 +10,19 @@ module ActiveRecord
10
10
  end
11
11
 
12
12
  def teardown
13
- pool.disconnect! if pool
13
+ pool.discard! if pool
14
14
  end
15
15
 
16
16
  def test_checkout_after_close
17
17
  connection = pool.connection
18
18
  assert connection.in_use?
19
+ assert_equal connection.object_id, pool.connection.object_id
19
20
 
20
- connection.close
21
+ connection.close # pool.checkin conn
21
22
  assert ! connection.in_use?
22
23
 
23
- assert_equal connection, pool.connection
24
- # assert pool.connection.in_use?
24
+ assert_equal connection.object_id, pool.connection.object_id
25
+ assert pool.connection.in_use?
25
26
  end
26
27
 
27
28
  def test_released_connection_moves_between_threads
@@ -134,8 +135,6 @@ module ActiveRecord
134
135
 
135
136
  # TODO this does not pass on built-in pool (MRI assumption) :
136
137
  #assert_equal 1, active_connections.size
137
- ensure
138
- pool.connections.each(&:close)
139
138
  end
140
139
 
141
140
  def test_remove_connection
@@ -159,15 +158,12 @@ module ActiveRecord
159
158
  end
160
159
 
161
160
  def test_active_connection?
162
- assert_false pool.active_connection?
161
+ assert ! pool.active_connection?
163
162
  assert pool.connection
164
- if ActiveRecord::VERSION::MAJOR >= 4
165
- assert_true pool.active_connection?
166
- else
167
- assert pool.active_connection?
168
- end
163
+ assert pool.active_connection? # true or returns owner thread (alias :in_use? :owner)
164
+ #assert_equal Thread, pool.active_connection?.class
169
165
  pool.release_connection
170
- assert_false pool.active_connection?
166
+ assert ! pool.active_connection?
171
167
  end
172
168
 
173
169
  def test_checkout_behaviour
@@ -177,7 +173,6 @@ module ActiveRecord
177
173
  threads << Thread.new(i) do
178
174
  connection = pool.connection
179
175
  assert_not_nil connection
180
- connection.close
181
176
  end
182
177
  end
183
178
 
@@ -185,7 +180,7 @@ module ActiveRecord
185
180
 
186
181
  Thread.new do
187
182
  assert pool.connection
188
- pool.connection.close
183
+ pool.connection.tables
189
184
  end.join
190
185
  end
191
186
 
@@ -332,7 +327,7 @@ module ActiveRecord
332
327
 
333
328
  def test_pooled_connection_remove
334
329
  # ActiveRecord::Base.establish_connection(@connection.merge({:pool => 2, :checkout_timeout => 0.5}))
335
- @pool.instance_variable_set(:@size, 2)
330
+ change_pool_size(2)
336
331
  # old_connection = ActiveRecord::Base.connection
337
332
  old_connection = @pool.connection
338
333
  # extra_connection = ActiveRecord::Base.connection_pool.checkout
@@ -340,11 +335,12 @@ module ActiveRecord
340
335
  # ActiveRecord::Base.connection_pool.remove(extra_connection)
341
336
  @pool.remove(extra_connection)
342
337
  # assert_equal ActiveRecord::Base.connection, old_connection
343
- assert_equal @pool.connection, old_connection
338
+ assert_equal old_connection.object_id, @pool.connection.object_id
344
339
  end
345
340
 
346
341
  def test_pooled_connection_checkin_two
347
342
  checkout_checkin_connections_loop 2, 3
343
+
348
344
  assert_equal 3, @connection_count
349
345
  assert_equal 0, @timed_out
350
346
  # assert_equal 2, ActiveRecord::Base.connection_pool.connections.size
@@ -355,8 +351,8 @@ module ActiveRecord
355
351
 
356
352
  def checkout_checkin_connections_loop(pool_size, loops)
357
353
  # ActiveRecord::Base.establish_connection(@connection.merge({:pool => pool_size, :checkout_timeout => 0.5}))
358
- @pool.instance_variable_set(:@size, pool_size)
359
- @pool.instance_variable_set(:@checkout_timeout, 0.5)
354
+ change_pool_size(pool_size)
355
+ change_pool_checkout_timeout(0.5)
360
356
 
361
357
  @connection_count = 0; @timed_out = 0
362
358
  loops.times do
@@ -376,6 +372,14 @@ module ActiveRecord
376
372
  end
377
373
  end
378
374
 
375
+ def change_pool_size(size)
376
+ @pool.instance_variable_set(:@size, size)
377
+ end
378
+
379
+ def change_pool_checkout_timeout(timeout)
380
+ @pool.instance_variable_set(:@checkout_timeout, timeout)
381
+ end
382
+
379
383
  private
380
384
 
381
385
  def active_connections(pool = self.pool)
@@ -384,4 +388,4 @@ module ActiveRecord
384
388
 
385
389
  end
386
390
  end
387
- end
391
+ end
data/test/test_helper.rb CHANGED
@@ -24,6 +24,8 @@ require 'arjdbc' if defined? JRUBY_VERSION
24
24
  require 'logger'
25
25
  ActiveRecord::Base.logger = Logger.new(STDOUT)
26
26
 
27
+ puts "testing with ActiveRecord #{ActiveRecord::VERSION::STRING}"
28
+
27
29
  #shared_pool = ENV['AR_POOL_SHARED'] ? # with AR_POOL_SHARED=true use default
28
30
  # ( ENV['AR_POOL_SHARED'] == 'true' ? shared_pool : ENV['AR_POOL_SHARED'] ) :
29
31
  # shared_pool
@@ -53,7 +55,7 @@ config[:'prepared_statements'] = prepared_statements if prepared_statements
53
55
  #jdbc_properties = { 'logUnclosedConnections' => true, 'loginTimeout' => 5 }
54
56
  #config[:'properties'] = jdbc_properties
55
57
  config[:'properties'] ||= {}
56
- config[:'properties']['useSSL'] ||= 'false' if config[:adapter].starts_with?('mysql')
58
+ config[:'properties']['useSSL'] ||= 'false' if config[:adapter].start_with?('mysql')
57
59
 
58
60
  checkout_timeout = ENV['AR_POOL_CHECKOUT_TIMEOUT'] || checkout_timeout
59
61
  config[:'checkout_timeout'] = checkout_timeout.to_f if checkout_timeout
@@ -112,13 +114,8 @@ end
112
114
  module ActiveRecord
113
115
  module Bogacs
114
116
 
115
- begin
116
- require 'concurrent/atomic/atomic_reference'
117
- Atomic = Concurrent::AtomicReference
118
- rescue LoadError
119
- require 'atomic'
120
- Atomic = ::Atomic
121
- end
117
+ require 'concurrent/atomic/atomic_reference'
118
+ Atomic = Concurrent::AtomicReference
122
119
 
123
120
  module TestHelper
124
121
 
@@ -161,7 +158,12 @@ module ActiveRecord
161
158
  module_function
162
159
 
163
160
  def current_connection_config
164
- if ActiveRecord::Base.respond_to?(:connection_config)
161
+ connected = ActiveRecord::Base.connection_pool.connected?
162
+ if ActiveRecord::Base.connection.respond_to?(:config)
163
+ ActiveRecord::Base.connection.config.tap do # always an updated config, e.g. after mysql2_connection(config)
164
+ ActiveRecord::Base.connection_pool.disconnect! unless connected # restore pool state to avoid test surprises
165
+ end
166
+ elsif ActiveRecord::Base.respond_to?(:connection_config)
165
167
  ActiveRecord::Base.connection_config
166
168
  else
167
169
  ActiveRecord::Base.connection_pool.spec.config
@@ -226,8 +228,8 @@ module ActiveRecord
226
228
  @@setup_jdbc_context = nil
227
229
 
228
230
  def setup_jdbc_context!
229
- load 'test/jars/tomcat-juli.jar'
230
- load 'test/jars/tomcat-catalina.jar'
231
+ load_jar 'test/jars/tomcat-juli.jar'
232
+ load_jar 'test/jars/tomcat-catalina.jar'
231
233
 
232
234
  java.lang.System.set_property(
233
235
  javax.naming.Context::INITIAL_CONTEXT_FACTORY,
@@ -251,7 +253,7 @@ module ActiveRecord
251
253
  end
252
254
 
253
255
  def build_tomcat_jdbc_data_source(ar_jdbc_config = AR_CONFIG)
254
- load 'test/jars/tomcat-jdbc.jar'
256
+ load_jar 'test/jars/tomcat-jdbc.jar'
255
257
 
256
258
  data_source = org.apache.tomcat.jdbc.pool.DataSource.new
257
259
  configure_dbcp_data_source(data_source, ar_jdbc_config)
@@ -262,7 +264,7 @@ module ActiveRecord
262
264
  end
263
265
 
264
266
  def build_tomcat_dbcp_data_source(ar_jdbc_config = AR_CONFIG)
265
- load 'test/jars/tomcat-dbcp.jar'
267
+ load_jar 'test/jars/tomcat-dbcp.jar'
266
268
 
267
269
  data_source = org.apache.tomcat.dbcp.dbcp.BasicDataSource.new
268
270
  configure_dbcp_data_source(data_source, ar_jdbc_config)
@@ -273,7 +275,7 @@ module ActiveRecord
273
275
  end
274
276
 
275
277
  def build_commons_dbcp_data_source(ar_jdbc_config = AR_CONFIG)
276
- load Dir.glob('test/jars/{commons-dbcp}*.jar').first
278
+ load_jar Dir.glob('test/jars/{commons-dbcp}*.jar').first
277
279
 
278
280
  data_source = org.apache.tomcat.dbcp.dbcp.BasicDataSource.new
279
281
  configure_dbcp_data_source(data_source, ar_jdbc_config)
@@ -299,11 +301,9 @@ module ActiveRecord
299
301
  properties.each { |name, value| db_properties.put(name, value.to_s) }
300
302
  data_source.setDbProperties db_properties
301
303
  else # Tomcat-DBCP / Commons DBCP2
302
- # format of the string must be: [propertyName=property;]
303
- connection_properties = properties.inject('') do
304
- |str, name, val| str << "[#{name}=#{val};]"; str
304
+ properties.each do |name, val|
305
+ data_source.addConnectionProperty name, val.to_s
305
306
  end
306
- data_source.setConnectionProperties connection_properties
307
307
  end
308
308
  end
309
309
  # JDBC pool tunings (some mapped from AR configuration) :
@@ -327,7 +327,7 @@ module ActiveRecord
327
327
  private :configure_dbcp_data_source
328
328
 
329
329
  def build_c3p0_data_source(ar_jdbc_config = AR_CONFIG)
330
- Dir.glob('test/jars/{c3p0,mchange-commons}*.jar').each { |jar| load jar }
330
+ Dir.glob('test/jars/{c3p0,mchange-commons}*.jar').each { |jar| load_jar jar }
331
331
 
332
332
  data_source = com.mchange.v2.c3p0.ComboPooledDataSource.new
333
333
  configure_c3p0_data_source(data_source, ar_jdbc_config)
@@ -373,15 +373,15 @@ module ActiveRecord
373
373
 
374
374
 
375
375
  def build_hikari_data_source(ar_jdbc_config = AR_CONFIG)
376
- unless hikari_jar = Dir.glob('test/jars/HikariCP*.jar').last
376
+ unless hikari_jar = Dir.glob('test/jars/HikariCP*.jar').sort.last
377
377
  raise 'HikariCP jar not found in test/jars directory'
378
378
  end
379
379
  if ( version = File.basename(hikari_jar, '.jar').match(/\-([\w\.\-]$)/) ) && version[1] < '2.3.9'
380
- Dir.glob('test/jars/{javassist,slf4j}*.jar').each { |jar| require jar }
380
+ Dir.glob('test/jars/{javassist,slf4j}*.jar').each { |jar| load_jar jar }
381
381
  else
382
- Dir.glob('test/jars/{slf4j}*.jar').each { |jar| require jar }
382
+ Dir.glob('test/jars/{slf4j}*.jar').each { |jar| load_jar jar }
383
383
  end
384
- require hikari_jar
384
+ load_jar hikari_jar
385
385
 
386
386
  configure_hikari_data_source(ar_jdbc_config)
387
387
  end
@@ -396,7 +396,12 @@ module ActiveRecord
396
396
 
397
397
  case driver
398
398
  when /mysql/i
399
- hikari_config.setDataSourceClassName 'com.mysql.jdbc.jdbc2.optional.MysqlDataSource'
399
+ data_source_class_name = if driver == 'com.mysql.cj.jdbc.Driver'
400
+ 'com.mysql.cj.jdbc.MysqlDataSource' # driver 8.0
401
+ else
402
+ 'com.mysql.jdbc.jdbc2.optional.MysqlDataSource' # old 5.x
403
+ end
404
+ hikari_config.setDataSourceClassName data_source_class_name
400
405
  hikari_config.addDataSourceProperty 'serverName', ar_jdbc_config[:host] || 'localhost'
401
406
  hikari_config.addDataSourceProperty 'databaseName', ar_jdbc_config[:database]
402
407
  hikari_config.addDataSourceProperty 'port', ar_jdbc_config[:port] if ar_jdbc_config[:port]
@@ -407,7 +412,7 @@ module ActiveRecord
407
412
  hikari_config.addDataSourceProperty 'password', ar_jdbc_config[:password]
408
413
  end
409
414
  ( ar_jdbc_config[:properties] || {} ).each do |name, val|
410
- hikari_config.addDataSourceProperty name.to_s, val.to_s
415
+ hikari_config.addDataSourceProperty name.to_s, val.to_s unless name.eql?('useLegacyDatetimeCode')
411
416
  end
412
417
  when /postgres/i
413
418
  hikari_config.setDataSourceClassName 'org.postgresql.ds.PGSimpleDataSource'
@@ -478,6 +483,16 @@ module ActiveRecord
478
483
 
479
484
  def jndi_name; 'jdbc/TestDB' end
480
485
 
486
+ private
487
+
488
+ def load_jar(jar)
489
+ abs_jar = File.expand_path(jar)
490
+ unless File.file?(abs_jar)
491
+ raise "path does not exist or is not a file: #{jar}"
492
+ end
493
+ load abs_jar
494
+ end
495
+
481
496
  end
482
497
  end
483
- end
498
+ end
metadata CHANGED
@@ -1,43 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-bogacs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
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: 2018-04-26 00:00:00.000000000 Z
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
15
15
  requirements:
16
- - - ">="
16
+ - - "<"
17
17
  - !ruby/object:Gem::Version
18
- version: '0.9'
19
- name: concurrent-ruby
18
+ version: '6'
19
+ name: activerecord
20
20
  prerelease: false
21
- type: :development
21
+ type: :runtime
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "<"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.9'
26
+ version: '6'
27
27
  - !ruby/object:Gem::Dependency
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '10.3'
32
+ version: '1.0'
33
+ name: concurrent-ruby
34
+ prerelease: false
35
+ type: :runtime
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
33
47
  name: rake
34
48
  prerelease: false
35
49
  type: :development
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
- - - "~>"
52
+ - - ">="
39
53
  - !ruby/object:Gem::Version
40
- version: '10.3'
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  requirement: !ruby/object:Gem::Requirement
43
57
  requirements:
@@ -59,6 +73,7 @@ executables: []
59
73
  extensions: []
60
74
  extra_rdoc_files: []
61
75
  files:
76
+ - ".github/workflows/test.yml"
62
77
  - ".gitignore"
63
78
  - ".travis.yml"
64
79
  - Gemfile
@@ -68,9 +83,11 @@ files:
68
83
  - activerecord-bogacs.gemspec
69
84
  - lib/active_record/bogacs.rb
70
85
  - lib/active_record/bogacs/autoload.rb
86
+ - lib/active_record/bogacs/connection_handler.rb
71
87
  - lib/active_record/bogacs/default_pool.rb
72
88
  - lib/active_record/bogacs/false_pool.rb
73
89
  - lib/active_record/bogacs/pool_support.rb
90
+ - lib/active_record/bogacs/railtie.rb
74
91
  - lib/active_record/bogacs/reaper.rb
75
92
  - lib/active_record/bogacs/shareable_pool.rb
76
93
  - lib/active_record/bogacs/thread_safe.rb
@@ -80,6 +97,7 @@ files:
80
97
  - lib/active_record/connection_adapters/adapter_compat.rb
81
98
  - lib/active_record/connection_adapters/pool_class.rb
82
99
  - lib/active_record/shared_connection.rb
100
+ - lib/activerecord-bogacs.rb
83
101
  - test/active_record/bogacs/default_pool_test.rb
84
102
  - test/active_record/bogacs/false_pool_test.rb
85
103
  - test/active_record/bogacs/reaper_test.rb
@@ -109,14 +127,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
127
  - !ruby/object:Gem::Version
110
128
  version: '0'
111
129
  requirements: []
112
- rubyforge_project:
113
- rubygems_version: 2.6.13
130
+ rubygems_version: 3.1.6
114
131
  signing_key:
115
132
  specification_version: 4
116
- summary: 'Bogacs contains several pool implementations that can be used as a replacement
117
- for ActiveRecord''s built-in pool, e.g. DefaultPool is an upstream tuned version
118
- with an API that is compatible with older AR versions. NOTE: you''ll need concurrent-ruby
119
- or thread_safe gem.'
133
+ summary: Bogacs contains several pool implementations that can be used as a replacement
134
+ for ActiveRecord's built-in pool, e.g. DefaultPool is an upstream tuned version
135
+ with an API that is compatible with older AR versions.
120
136
  test_files:
121
137
  - test/active_record/bogacs/default_pool_test.rb
122
138
  - test/active_record/bogacs/false_pool_test.rb