activerecord-bogacs 0.4.0 → 0.4.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/.travis.yml +17 -4
- data/lib/active_record/bogacs/default_pool.rb +56 -225
- data/lib/active_record/bogacs/false_pool.rb +2 -2
- data/lib/active_record/bogacs/pool_support.rb +44 -0
- data/lib/active_record/bogacs/version.rb +1 -1
- data/test/active_record/bogacs/default_pool_test.rb +2 -0
- data/test/active_record/bogacs/false_pool_test.rb +7 -6
- data/test/active_record/connection_pool_test_methods.rb +46 -0
- data/test/test_helper.rb +11 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0aec44c1b08bd47f913dcce2eba41e1d30b1fa0
|
4
|
+
data.tar.gz: a506eb318972490b316604732aded93e5079e5d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc20088b6faeba8de52781af835d3cc078017bfcb7139b14e96d9f503fc3019340bbbe5fc0ae1ce8a000fb42a620a1fc3fda114b2dbe057f36d5e974ed892b28
|
7
|
+
data.tar.gz: 4600c5ed962dfb2682cc9f5911292442ac90951af19c3511d069b97175a5114f4c4f05de46bbfad25f5ed821c44388946b6336b84c4b636f08b498f57fae68b7
|
data/.travis.yml
CHANGED
@@ -22,7 +22,7 @@ script:
|
|
22
22
|
env:
|
23
23
|
- JRUBY_OPTS="$JRUBY_OPTS" AR_ADAPTER=mysql AR_VERSION="~> 4.1.9" HIKARI_VERSION="2.3.12"
|
24
24
|
- JRUBY_OPTS="$JRUBY_OPTS" AR_ADAPTER=postgresql AR_VERSION="~> 4.1.9" HIKARI_VERSION="2.3.2-java6"
|
25
|
-
- JRUBY_OPTS="$JRUBY_OPTS" AR_ADAPTER=mysql AR_VERSION="~> 4.1.
|
25
|
+
- JRUBY_OPTS="$JRUBY_OPTS" AR_ADAPTER=mysql AR_VERSION="~> 4.1.11" HIKARI_VERSION="2.0.1-java6"
|
26
26
|
- JRUBY_OPTS="$JRUBY_OPTS" AR_ADAPTER=postgresql AR_VERSION="~> 3.2.18" HIKARI_VERSION="1.4.0"
|
27
27
|
- JRUBY_OPTS="--1.8 $JRUBY_OPTS" AR_ADAPTER=mysql AR_VERSION="~> 3.2.18" HIKARI_VERSION="2.2.5-java6"
|
28
28
|
matrix:
|
@@ -36,15 +36,28 @@ matrix:
|
|
36
36
|
env: JRUBY_OPTS="$JRUBY_OPTS" AR_ADAPTER=postgresql AR_VERSION="~> 4.1.9" HIKARI_VERSION="2.3.2-java6"
|
37
37
|
jdk: oraclejdk8
|
38
38
|
- rvm: jruby-1.7.22
|
39
|
-
env: JRUBY_OPTS="$JRUBY_OPTS" AR_ADAPTER=mysql AR_VERSION="~> 4.1.
|
39
|
+
env: JRUBY_OPTS="$JRUBY_OPTS" AR_ADAPTER=mysql AR_VERSION="~> 4.1.13" HIKARI_VERSION="2.0.1-java6"
|
40
40
|
jdk: oraclejdk8
|
41
41
|
- rvm: jruby-1.7.22
|
42
42
|
env: JRUBY_OPTS="--1.8 $JRUBY_OPTS" AR_ADAPTER=mysql AR_VERSION="~> 3.2.18" HIKARI_VERSION="2.2.5-java6"
|
43
43
|
jdk: oraclejdk8
|
44
44
|
include:
|
45
45
|
- rvm: jruby-9.0.1.0
|
46
|
-
env: JRUBY_OPTS="$JRUBY_OPTS" AR_ADAPTER=mysql AR_VERSION="~> 4.1.
|
46
|
+
env: JRUBY_OPTS="$JRUBY_OPTS" AR_ADAPTER=mysql AR_VERSION="~> 4.1.13" HIKARI_VERSION="2.2.5-java6"
|
47
47
|
jdk: oraclejdk7
|
48
48
|
- rvm: jruby-9.0.1.0
|
49
49
|
env: JRUBY_OPTS="$JRUBY_OPTS" AR_ADAPTER=mysql AR_VERSION="~> 3.2.18" HIKARI_VERSION="2.3.9"
|
50
|
-
jdk: oraclejdk8
|
50
|
+
jdk: oraclejdk8
|
51
|
+
# AR 4.2
|
52
|
+
- rvm: jruby-1.7.22
|
53
|
+
env: JRUBY_OPTS="$JRUBY_OPTS" AR_ADAPTER=mysql AR_VERSION="~> 4.1.13" HIKARI_VERSION="2.2.5-java6"
|
54
|
+
jdk: oraclejdk7
|
55
|
+
- rvm: jruby-9.0.1.0
|
56
|
+
env: JRUBY_OPTS="$JRUBY_OPTS" AR_ADAPTER=mysql AR_VERSION="~> 4.2.4" HIKARI_VERSION="2.3.12"
|
57
|
+
jdk: oraclejdk8
|
58
|
+
- rvm: jruby-1.7.22
|
59
|
+
env: JRUBY_OPTS="$JRUBY_OPTS" AR_ADAPTER=postgresql AR_VERSION="~> 4.2.4" HIKARI_VERSION="2.2.5-java6"
|
60
|
+
jdk: oraclejdk8
|
61
|
+
- rvm: jruby-9.0.1.0
|
62
|
+
env: JRUBY_OPTS="$JRUBY_OPTS" AR_ADAPTER=postgresql AR_VERSION="~> 4.1.13" HIKARI_VERSION="2.3.12"
|
63
|
+
jdk: oraclejdk7
|
@@ -33,14 +33,16 @@ module ActiveRecord
|
|
33
33
|
# There are several connection-pooling-related options that you can add to
|
34
34
|
# your database connection configuration:
|
35
35
|
#
|
36
|
-
# *
|
37
|
-
# *
|
36
|
+
# * **pool**: number indicating size of connection pool (default 5)
|
37
|
+
# * **checkout_timeout**: number of seconds to block and wait for a connection
|
38
38
|
# before giving up and raising a timeout error (default 5 seconds).
|
39
|
-
# *
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
39
|
+
# * **pool_initial**: number of connections to pre-initialize when the pool
|
40
|
+
# is created (default 0).
|
41
|
+
# * **reaping_frequency**: frequency in seconds to periodically run a reaper,
|
42
|
+
# which attempts to find and close "dead" connections (can occur if a caller
|
43
|
+
# forgets to close a connection at the end of a thread or a thread dies unexpectedly)
|
44
|
+
# Default is `nil`, which means don't run the periodical Reaper at all (reaping
|
45
|
+
# will still happen occasionally).
|
44
46
|
class DefaultPool
|
45
47
|
# Threadsafe, fair, FIFO queue. Meant to be used by ConnectionPool
|
46
48
|
# with which it shares a Monitor. But could be a generic Queue.
|
@@ -158,7 +160,7 @@ module ActiveRecord
|
|
158
160
|
|
159
161
|
yield if block_given?
|
160
162
|
|
161
|
-
|
163
|
+
while true
|
162
164
|
@cond.wait(timeout - elapsed)
|
163
165
|
|
164
166
|
return remove if any?
|
@@ -227,8 +229,8 @@ module ActiveRecord
|
|
227
229
|
if spec.config[:pool]
|
228
230
|
@size = spec.config[:pool].to_i
|
229
231
|
else
|
230
|
-
if defined? Rails.env && Rails.env.
|
231
|
-
logger && logger.debug("pool: option not set, using
|
232
|
+
if defined? Rails.env && ( (! Rails.env.development? && ! Rails.env.test?) rescue nil )
|
233
|
+
logger && logger.debug("pool: option not set, using default size: 5")
|
232
234
|
end
|
233
235
|
@size = 5
|
234
236
|
end
|
@@ -253,6 +255,8 @@ module ActiveRecord
|
|
253
255
|
#
|
254
256
|
# #connection can be called any number of times; the connection is
|
255
257
|
# held in a hash keyed by the thread id.
|
258
|
+
#
|
259
|
+
# @return [ActiveRecord::ConnectionAdapters::AbstractAdapter]
|
256
260
|
def connection
|
257
261
|
connection_id = current_connection_id
|
258
262
|
unless conn = @reserved_connections.fetch(connection_id, nil)
|
@@ -264,6 +268,8 @@ module ActiveRecord
|
|
264
268
|
end
|
265
269
|
|
266
270
|
# Is there an open connection that is being used for the current thread?
|
271
|
+
#
|
272
|
+
# @return [true, false]
|
267
273
|
def active_connection?
|
268
274
|
connection_id = current_connection_id
|
269
275
|
if conn = @reserved_connections.fetch(connection_id, nil)
|
@@ -286,6 +292,8 @@ module ActiveRecord
|
|
286
292
|
# If a connection already exists yield it to the block. If no connection
|
287
293
|
# exists checkout a connection, yield it to the block, and checkin the
|
288
294
|
# connection when finished.
|
295
|
+
#
|
296
|
+
# @yield [ActiveRecord::ConnectionAdapters::AbstractAdapter]
|
289
297
|
def with_connection
|
290
298
|
connection_id = current_connection_id
|
291
299
|
fresh_connection = true unless active_connection?
|
@@ -295,6 +303,8 @@ module ActiveRecord
|
|
295
303
|
end
|
296
304
|
|
297
305
|
# Returns true if a connection has already been opened.
|
306
|
+
#
|
307
|
+
# @return [true, false]
|
298
308
|
def connected?
|
299
309
|
@connections.size > 0 # synchronize { @connections.any? }
|
300
310
|
end
|
@@ -344,6 +354,7 @@ module ActiveRecord
|
|
344
354
|
|
345
355
|
# Return any checked-out connections back to the pool by threads that
|
346
356
|
# are no longer alive.
|
357
|
+
# @private AR 3.2 compatibility
|
347
358
|
def clear_stale_cached_connections!
|
348
359
|
keys = Thread.list.find_all { |t| t.alive? }.map(&:object_id)
|
349
360
|
keys = @reserved_connections.keys - keys
|
@@ -354,60 +365,58 @@ module ActiveRecord
|
|
354
365
|
end
|
355
366
|
end if ActiveRecord::VERSION::MAJOR < 4
|
356
367
|
|
357
|
-
# Check-out a database connection from the pool,
|
358
|
-
#
|
368
|
+
# Check-out a database connection from the pool, callers are expected to
|
369
|
+
# call #checkin when the connection is no longer needed, so that others
|
370
|
+
# can use it.
|
359
371
|
#
|
360
372
|
# This is done by either returning and leasing existing connection, or by
|
361
373
|
# creating a new connection and leasing it.
|
362
374
|
#
|
363
|
-
#
|
364
|
-
#
|
365
|
-
#
|
366
|
-
#
|
367
|
-
# Returns: an AbstractAdapter object.
|
368
|
-
#
|
369
|
-
# Raises:
|
370
|
-
# - ConnectionTimeoutError: no connection can be obtained from the pool.
|
375
|
+
# @return [ActiveRecord::ConnectionAdapters::AbstractAdapter]
|
376
|
+
# @raise [ActiveRecord::ConnectionTimeoutError] if all connections are leased
|
377
|
+
# and the pool is at capacity (meaning the number of currently leased
|
378
|
+
# connections is greater than or equal to the size limit set)
|
371
379
|
def checkout
|
380
|
+
conn = nil
|
372
381
|
synchronize do
|
373
382
|
conn = acquire_connection
|
374
383
|
conn.lease
|
375
|
-
checkout_and_verify(conn)
|
376
384
|
end
|
385
|
+
checkout_and_verify(conn)
|
377
386
|
end
|
378
387
|
|
379
|
-
# Check-in a database connection back into the pool
|
380
|
-
# no longer need this connection.
|
388
|
+
# Check-in a database connection back into the pool.
|
381
389
|
#
|
382
|
-
#
|
383
|
-
# calling
|
390
|
+
# @param [ActiveRecord::ConnectionAdapters::AbstractAdapter] connection
|
391
|
+
# object, which was obtained earlier by calling #checkout on this pool
|
392
|
+
# @see #checkout
|
384
393
|
def checkin(conn, released = nil)
|
385
394
|
synchronize do
|
386
|
-
conn
|
387
|
-
conn.expire
|
388
|
-
end
|
395
|
+
_run_checkin_callbacks(conn)
|
389
396
|
|
390
|
-
release conn.owner unless released
|
397
|
+
release conn, conn.owner unless released
|
391
398
|
|
392
399
|
@available.add conn
|
393
400
|
end
|
394
401
|
end
|
395
402
|
|
396
|
-
# Remove a connection from the connection pool. The connection
|
397
|
-
# remain open and active but will no longer be managed by this pool.
|
403
|
+
# Remove a connection from the connection pool. The returned connection
|
404
|
+
# will remain open and active but will no longer be managed by this pool.
|
405
|
+
#
|
406
|
+
# @return [ActiveRecord::ConnectionAdapters::AbstractAdapter]
|
398
407
|
def remove(conn)
|
399
408
|
synchronize do
|
400
409
|
@connections.delete conn
|
401
410
|
@available.delete conn
|
402
411
|
|
403
|
-
release conn.owner
|
412
|
+
release conn, conn.owner
|
404
413
|
|
405
414
|
@available.add checkout_new_connection if @available.any_waiting?
|
406
415
|
end
|
407
416
|
end
|
408
417
|
|
409
418
|
# Recover lost connections for the pool. A lost connection can occur if
|
410
|
-
# a
|
419
|
+
# a caller forgets to #checkin a connection for a given thread when its done
|
411
420
|
# or a thread dies unexpectedly.
|
412
421
|
def reap
|
413
422
|
stale_connections = synchronize do
|
@@ -449,25 +458,25 @@ module ActiveRecord
|
|
449
458
|
end
|
450
459
|
end
|
451
460
|
|
452
|
-
def release(owner)
|
461
|
+
def release(conn, owner)
|
453
462
|
thread_id = owner.object_id
|
454
|
-
@reserved_connections
|
463
|
+
if @reserved_connections[thread_id] == conn
|
464
|
+
@reserved_connections.delete thread_id
|
465
|
+
end
|
455
466
|
end
|
456
467
|
|
457
468
|
def checkout_new_connection
|
458
469
|
raise ConnectionNotEstablished unless @automatic_reconnect
|
459
470
|
|
460
|
-
|
461
|
-
|
462
|
-
@connections <<
|
463
|
-
|
471
|
+
conn = new_connection
|
472
|
+
conn.pool = self
|
473
|
+
@connections << conn
|
474
|
+
conn
|
464
475
|
end
|
465
476
|
|
466
|
-
def checkout_and_verify(
|
467
|
-
|
468
|
-
|
469
|
-
end
|
470
|
-
c
|
477
|
+
def checkout_and_verify(conn)
|
478
|
+
_run_checkout_callbacks(conn)
|
479
|
+
conn
|
471
480
|
end
|
472
481
|
|
473
482
|
def prefill_initial_connections
|
@@ -481,189 +490,11 @@ module ActiveRecord
|
|
481
490
|
conns
|
482
491
|
end
|
483
492
|
|
484
|
-
|
485
|
-
|
486
|
-
end
|
487
|
-
|
488
|
-
end
|
489
|
-
|
490
|
-
=begin
|
491
|
-
|
492
|
-
# ConnectionHandler is a collection of ConnectionPool objects. It is used
|
493
|
-
# for keeping separate connection pools for Active Record models that connect
|
494
|
-
# to different databases.
|
495
|
-
#
|
496
|
-
# For example, suppose that you have 5 models, with the following hierarchy:
|
497
|
-
#
|
498
|
-
# |
|
499
|
-
# +-- Book
|
500
|
-
# | |
|
501
|
-
# | +-- ScaryBook
|
502
|
-
# | +-- GoodBook
|
503
|
-
# +-- Author
|
504
|
-
# +-- BankAccount
|
505
|
-
#
|
506
|
-
# Suppose that Book is to connect to a separate database (i.e. one other
|
507
|
-
# than the default database). Then Book, ScaryBook and GoodBook will all use
|
508
|
-
# the same connection pool. Likewise, Author and BankAccount will use the
|
509
|
-
# same connection pool. However, the connection pool used by Author/BankAccount
|
510
|
-
# is not the same as the one used by Book/ScaryBook/GoodBook.
|
511
|
-
#
|
512
|
-
# Normally there is only a single ConnectionHandler instance, accessible via
|
513
|
-
# ActiveRecord::Base.connection_handler. Active Record models use this to
|
514
|
-
# determine the connection pool that they should use.
|
515
|
-
class ConnectionHandler
|
516
|
-
def initialize
|
517
|
-
# These caches are keyed by klass.name, NOT klass. Keying them by klass
|
518
|
-
# alone would lead to memory leaks in development mode as all previous
|
519
|
-
# instances of the class would stay in memory.
|
520
|
-
@owner_to_pool = ThreadSafe::Cache.new(:initial_capacity => 2) do |h,k|
|
521
|
-
h[k] = ThreadSafe::Cache.new(:initial_capacity => 2)
|
522
|
-
end
|
523
|
-
@class_to_pool = ThreadSafe::Cache.new(:initial_capacity => 2) do |h,k|
|
524
|
-
h[k] = ThreadSafe::Cache.new
|
525
|
-
end
|
526
|
-
end
|
527
|
-
|
528
|
-
def connection_pool_list
|
529
|
-
owner_to_pool.values.compact
|
530
|
-
end
|
531
|
-
|
532
|
-
def connection_pools
|
533
|
-
ActiveSupport::Deprecation.warn(
|
534
|
-
"In the next release, this will return the same as #connection_pool_list. " \
|
535
|
-
"(An array of pools, rather than a hash mapping specs to pools.)"
|
536
|
-
)
|
537
|
-
Hash[connection_pool_list.map { |pool| [pool.spec, pool] }]
|
538
|
-
end
|
539
|
-
|
540
|
-
def establish_connection(owner, spec)
|
541
|
-
@class_to_pool.clear
|
542
|
-
raise RuntimeError, "Anonymous class is not allowed." unless owner.name
|
543
|
-
owner_to_pool[owner.name] = ConnectionAdapters::ConnectionPool.new(spec)
|
544
|
-
end
|
545
|
-
|
546
|
-
# Returns true if there are any active connections among the connection
|
547
|
-
# pools that the ConnectionHandler is managing.
|
548
|
-
def active_connections?
|
549
|
-
connection_pool_list.any?(&:active_connection?)
|
550
|
-
end
|
551
|
-
|
552
|
-
# Returns any connections in use by the current thread back to the pool,
|
553
|
-
# and also returns connections to the pool cached by threads that are no
|
554
|
-
# longer alive.
|
555
|
-
def clear_active_connections!
|
556
|
-
connection_pool_list.each(&:release_connection)
|
557
|
-
end
|
558
|
-
|
559
|
-
# Clears the cache which maps classes.
|
560
|
-
def clear_reloadable_connections!
|
561
|
-
connection_pool_list.each(&:clear_reloadable_connections!)
|
562
|
-
end
|
563
|
-
|
564
|
-
def clear_all_connections!
|
565
|
-
connection_pool_list.each(&:disconnect!)
|
566
|
-
end
|
493
|
+
#@@logger = nil
|
494
|
+
def logger; ::ActiveRecord::Base.logger end
|
495
|
+
#def logger=(logger); @@logger = logger end
|
567
496
|
|
568
|
-
# Locate the connection of the nearest super class. This can be an
|
569
|
-
# active or defined connection: if it is the latter, it will be
|
570
|
-
# opened and set as the active connection for the class it was defined
|
571
|
-
# for (not necessarily the current class).
|
572
|
-
def retrieve_connection(klass) #:nodoc:
|
573
|
-
pool = retrieve_connection_pool(klass)
|
574
|
-
(pool && pool.connection) or raise ConnectionNotEstablished
|
575
|
-
end
|
576
|
-
|
577
|
-
# Returns true if a connection that's accessible to this class has
|
578
|
-
# already been opened.
|
579
|
-
def connected?(klass)
|
580
|
-
conn = retrieve_connection_pool(klass)
|
581
|
-
conn && conn.connected?
|
582
|
-
end
|
583
|
-
|
584
|
-
# Remove the connection for this class. This will close the active
|
585
|
-
# connection and the defined connection (if they exist). The result
|
586
|
-
# can be used as an argument for establish_connection, for easily
|
587
|
-
# re-establishing the connection.
|
588
|
-
def remove_connection(owner)
|
589
|
-
if pool = owner_to_pool.delete(owner.name)
|
590
|
-
@class_to_pool.clear
|
591
|
-
pool.automatic_reconnect = false
|
592
|
-
pool.disconnect!
|
593
|
-
pool.spec.config
|
594
|
-
end
|
595
|
-
end
|
596
|
-
|
597
|
-
# Retrieving the connection pool happens a lot so we cache it in @class_to_pool.
|
598
|
-
# This makes retrieving the connection pool O(1) once the process is warm.
|
599
|
-
# When a connection is established or removed, we invalidate the cache.
|
600
|
-
#
|
601
|
-
# Ideally we would use #fetch here, as class_to_pool[klass] may sometimes be nil.
|
602
|
-
# However, benchmarking (https://gist.github.com/jonleighton/3552829) showed that
|
603
|
-
# #fetch is significantly slower than #[]. So in the nil case, no caching will
|
604
|
-
# take place, but that's ok since the nil case is not the common one that we wish
|
605
|
-
# to optimise for.
|
606
|
-
def retrieve_connection_pool(klass)
|
607
|
-
class_to_pool[klass.name] ||= begin
|
608
|
-
until pool = pool_for(klass)
|
609
|
-
klass = klass.superclass
|
610
|
-
break unless klass <= Base
|
611
|
-
end
|
612
|
-
|
613
|
-
class_to_pool[klass.name] = pool
|
614
|
-
end
|
615
|
-
end
|
616
|
-
|
617
|
-
private
|
618
|
-
|
619
|
-
def owner_to_pool
|
620
|
-
@owner_to_pool[Process.pid]
|
621
|
-
end
|
622
|
-
|
623
|
-
def class_to_pool
|
624
|
-
@class_to_pool[Process.pid]
|
625
|
-
end
|
626
|
-
|
627
|
-
def pool_for(owner)
|
628
|
-
owner_to_pool.fetch(owner.name) {
|
629
|
-
if ancestor_pool = pool_from_any_process_for(owner)
|
630
|
-
# A connection was established in an ancestor process that must have
|
631
|
-
# subsequently forked. We can't reuse the connection, but we can copy
|
632
|
-
# the specification and establish a new connection with it.
|
633
|
-
establish_connection owner, ancestor_pool.spec
|
634
|
-
else
|
635
|
-
owner_to_pool[owner.name] = nil
|
636
|
-
end
|
637
|
-
}
|
638
|
-
end
|
639
|
-
|
640
|
-
def pool_from_any_process_for(owner)
|
641
|
-
owner_to_pool = @owner_to_pool.values.find { |v| v[owner.name] }
|
642
|
-
owner_to_pool && owner_to_pool[owner.name]
|
643
|
-
end
|
644
497
|
end
|
645
498
|
|
646
|
-
class ConnectionManagement
|
647
|
-
def initialize(app)
|
648
|
-
@app = app
|
649
|
-
end
|
650
|
-
|
651
|
-
def call(env)
|
652
|
-
testing = env.key?('rack.test')
|
653
|
-
|
654
|
-
response = @app.call(env)
|
655
|
-
response[2] = ::Rack::BodyProxy.new(response[2]) do
|
656
|
-
ActiveRecord::Base.clear_active_connections! unless testing
|
657
|
-
end
|
658
|
-
|
659
|
-
response
|
660
|
-
rescue Exception
|
661
|
-
ActiveRecord::Base.clear_active_connections! unless testing
|
662
|
-
raise
|
663
|
-
end
|
664
|
-
end
|
665
|
-
|
666
|
-
=end
|
667
|
-
|
668
499
|
end
|
669
500
|
end
|
@@ -144,7 +144,7 @@ module ActiveRecord
|
|
144
144
|
#synchronize do
|
145
145
|
conn = checkout_new_connection # acquire_connection
|
146
146
|
conn.lease
|
147
|
-
conn
|
147
|
+
_run_checkout_callbacks(conn) # checkout_and_verify(conn)
|
148
148
|
conn
|
149
149
|
#end
|
150
150
|
end
|
@@ -157,7 +157,7 @@ module ActiveRecord
|
|
157
157
|
def checkin(conn, do_release = true)
|
158
158
|
release(conn) if do_release
|
159
159
|
#synchronize do
|
160
|
-
conn
|
160
|
+
_run_checkin_callbacks(conn)
|
161
161
|
#release conn
|
162
162
|
#@available.add conn
|
163
163
|
#end
|
@@ -36,6 +36,50 @@ module ActiveRecord
|
|
36
36
|
end
|
37
37
|
end if ActiveRecord::VERSION::MAJOR < 4
|
38
38
|
|
39
|
+
private
|
40
|
+
|
41
|
+
if ActiveRecord::VERSION::STRING > '4.2'
|
42
|
+
|
43
|
+
def _run_checkin_callbacks(conn)
|
44
|
+
if conn.respond_to?(:_run_checkin_callbacks)
|
45
|
+
conn._run_checkin_callbacks do
|
46
|
+
conn.expire
|
47
|
+
end
|
48
|
+
else
|
49
|
+
conn.run_callbacks :checkin do
|
50
|
+
conn.expire
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def _run_checkout_callbacks(conn)
|
56
|
+
if conn.respond_to?(:_run_checkout_callbacks)
|
57
|
+
conn._run_checkout_callbacks do
|
58
|
+
conn.verify!
|
59
|
+
end
|
60
|
+
else
|
61
|
+
conn.run_callbacks :checkout do
|
62
|
+
conn.verify!
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
else
|
68
|
+
|
69
|
+
def _run_checkin_callbacks(conn)
|
70
|
+
conn.run_callbacks :checkin do
|
71
|
+
conn.expire
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def _run_checkout_callbacks(conn)
|
76
|
+
conn.run_callbacks :checkout do
|
77
|
+
conn.verify!
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
39
83
|
end
|
40
84
|
end
|
41
85
|
end
|
@@ -12,8 +12,6 @@ module ActiveRecord
|
|
12
12
|
# extend Bogacs::TestHelper
|
13
13
|
extend Bogacs::JndiTestHelper
|
14
14
|
|
15
|
-
@@data_source = nil
|
16
|
-
|
17
15
|
def self.startup
|
18
16
|
return if self == TestBase
|
19
17
|
|
@@ -25,7 +23,11 @@ module ActiveRecord
|
|
25
23
|
def self.shutdown
|
26
24
|
return if self == TestBase
|
27
25
|
|
28
|
-
|
26
|
+
begin
|
27
|
+
close_data_source
|
28
|
+
ensure
|
29
|
+
@@data_source = nil
|
30
|
+
end
|
29
31
|
|
30
32
|
ActiveRecord::Base.connection_pool.disconnect!
|
31
33
|
ConnectionAdapters::ConnectionHandler.connection_pool_class = ConnectionAdapters::ConnectionPool
|
@@ -46,6 +48,8 @@ module ActiveRecord
|
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
51
|
+
@@data_source = nil
|
52
|
+
|
49
53
|
def self.init_data_source
|
50
54
|
setup_jdbc_context
|
51
55
|
bind_data_source @@data_source = build_data_source(raw_config)
|
@@ -343,9 +347,6 @@ module ActiveRecord
|
|
343
347
|
com.zaxxer.hikari.HikariDataSource.class_eval do
|
344
348
|
field_reader :pool unless method_defined? :pool
|
345
349
|
end
|
346
|
-
com.zaxxer.hikari.pool.HikariPool.class_eval do
|
347
|
-
field_reader :isShutdown unless method_defined? :isShutdown
|
348
|
-
end
|
349
350
|
|
350
351
|
data_source
|
351
352
|
end
|
@@ -329,6 +329,52 @@ module ActiveRecord
|
|
329
329
|
# assert_raises { handler.establish_connection anonymous, nil }
|
330
330
|
#end
|
331
331
|
|
332
|
+
def test_pooled_connection_remove
|
333
|
+
# ActiveRecord::Base.establish_connection(@connection.merge({:pool => 2, :checkout_timeout => 0.5}))
|
334
|
+
@pool.instance_variable_set(:@size, 2)
|
335
|
+
# old_connection = ActiveRecord::Base.connection
|
336
|
+
old_connection = @pool.connection
|
337
|
+
# extra_connection = ActiveRecord::Base.connection_pool.checkout
|
338
|
+
extra_connection = @pool.checkout
|
339
|
+
# ActiveRecord::Base.connection_pool.remove(extra_connection)
|
340
|
+
@pool.remove(extra_connection)
|
341
|
+
# assert_equal ActiveRecord::Base.connection, old_connection
|
342
|
+
assert_equal @pool.connection, old_connection
|
343
|
+
end
|
344
|
+
|
345
|
+
def test_pooled_connection_checkin_two
|
346
|
+
checkout_checkin_connections_loop 2, 3
|
347
|
+
assert_equal 3, @connection_count
|
348
|
+
assert_equal 0, @timed_out
|
349
|
+
# assert_equal 2, ActiveRecord::Base.connection_pool.connections.size
|
350
|
+
assert_equal 2, @pool.connections.size
|
351
|
+
end
|
352
|
+
|
353
|
+
protected
|
354
|
+
|
355
|
+
def checkout_checkin_connections_loop(pool_size, loops)
|
356
|
+
# ActiveRecord::Base.establish_connection(@connection.merge({:pool => pool_size, :checkout_timeout => 0.5}))
|
357
|
+
@pool.instance_variable_set(:@size, pool_size)
|
358
|
+
@pool.instance_variable_set(:@checkout_timeout, 0.5)
|
359
|
+
|
360
|
+
@connection_count = 0; @timed_out = 0
|
361
|
+
loops.times do
|
362
|
+
begin
|
363
|
+
# conn = ActiveRecord::Base.connection_pool.checkout
|
364
|
+
conn = @pool.checkout
|
365
|
+
# ActiveRecord::Base.connection_pool.checkin conn
|
366
|
+
@pool.checkin conn
|
367
|
+
|
368
|
+
@connection_count += 1
|
369
|
+
|
370
|
+
# ActiveRecord::Base.connection.tables
|
371
|
+
@pool.connection.tables
|
372
|
+
rescue ActiveRecord::ConnectionTimeoutError
|
373
|
+
@timed_out += 1
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
332
378
|
private
|
333
379
|
|
334
380
|
def active_connections(pool = self.pool)
|
data/test/test_helper.rb
CHANGED
@@ -349,7 +349,7 @@ module ActiveRecord
|
|
349
349
|
|
350
350
|
if ar_jdbc_config[:properties]
|
351
351
|
properties = java.util.Properties.new
|
352
|
-
|
352
|
+
ar_jdbc_config[:properties].each { |key, val| properties.put key.to_s, val.to_s }
|
353
353
|
data_source.setProperties properties
|
354
354
|
end
|
355
355
|
# JDBC pool tunings (some mapped from AR configuration) :
|
@@ -371,7 +371,15 @@ module ActiveRecord
|
|
371
371
|
|
372
372
|
|
373
373
|
def build_hikari_data_source(ar_jdbc_config = AR_CONFIG)
|
374
|
-
Dir.glob('test/jars/
|
374
|
+
unless hikari_jar = Dir.glob('test/jars/HikariCP*.jar').last
|
375
|
+
raise 'HikariCP jar not found in test/jars directory'
|
376
|
+
end
|
377
|
+
if ( version = File.basename(hikari_jar, '.jar').match(/\-([\w\.\-]$)/) ) && version[1] < '2.3.9'
|
378
|
+
Dir.glob('test/jars/{javassist,slf4j}*.jar').each { |jar| require jar }
|
379
|
+
else
|
380
|
+
Dir.glob('test/jars/{slf4j}*.jar').each { |jar| require jar }
|
381
|
+
end
|
382
|
+
require hikari_jar
|
375
383
|
|
376
384
|
configure_hikari_data_source(ar_jdbc_config)
|
377
385
|
end
|
@@ -400,7 +408,7 @@ module ActiveRecord
|
|
400
408
|
hikari_config.setDataSourceClassName 'org.postgresql.ds.PGSimpleDataSource'
|
401
409
|
hikari_config.addDataSourceProperty 'serverName', ar_jdbc_config[:host] || 'localhost'
|
402
410
|
hikari_config.addDataSourceProperty 'databaseName', ar_jdbc_config[:database]
|
403
|
-
hikari_config.addDataSourceProperty '
|
411
|
+
hikari_config.addDataSourceProperty 'portNumber', ar_jdbc_config[:port] if ar_jdbc_config[:port]
|
404
412
|
if ar_jdbc_config[:username]
|
405
413
|
hikari_config.addDataSourceProperty 'user', ar_jdbc_config[:username]
|
406
414
|
end
|
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.4.
|
4
|
+
version: 0.4.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: 2015-
|
11
|
+
date: 2015-11-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|