activerecord-bogacs 0.5.1 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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